%%%============================================================================== % WinEdt pragmas % !Mode:: "TeX:EN" % Default Compile engines: % !TEX program = pdflatex % !PDFTeXify ext = --enable-etex --restrict-write18 % !PDFLaTeX ext = --enable-etex --restrict-write18 % !BIB program = biber %%%============================================================================== %% Copyright 2025-present by Alceu Frigeri %% %% This work may be distributed and/or modified under the conditions of %% %% * The [LaTeX Project Public License](http://www.latex-project.org/lppl.txt), %% version 1.3c (or later), and/or %% * The [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html), %% version 3 (or later) %% %% This work has the LPPL maintenance status *maintained*. %% %% The Current Maintainer of this work is Alceu Frigeri %% %% This is version {1.1} {2025/05/11} %% %% The list of files that compose this work can be found in the README.md file at %% https://ctan.org/pkg/switch %% %%%============================================================================== \documentclass[10pt]{article} \RequirePackage[verbose,a4paper,marginparwidth=27.5mm,top=2.5cm,bottom=1.5cm,hmargin={40mm,20mm},marginparsep=2.5mm,columnsep=10mm,asymmetric]{geometry} \usepackage{codedescribe} \RequirePackage[inline]{enumitem} \SetEnumitemKey{miditemsep}{parsep=0ex,itemsep=0.4ex} %%\usepackage[american,siunitx,cuteinductors,smartlabels,arrowmos,EFvoltages,betterproportions]{circuitikz} %%\usetikzlibrary{math} \usepackage{switch} \RequirePackage[backend=biber]{biblatex} \addbibresource{switch.bib} \RequirePackage[hidelinks,hypertexnames=false]{hyperref} \begin{document} \tstitle{ author={Alceu Frigeri\footnote{\tsverb{https://github.com/alceu-frigeri/switch}}}, date={\tsdate}, title={The switch Package\break Version \PkgInfo{switch}{version}} } \begin{typesetabstract} This package offers two commands aimed at implementing a switch/case alike command. \end{typesetabstract} \tableofcontents \section{Introduction} There are many ways of implementing a switch case programming structure. Notably, one can use \tsobj{\str_case:nn} from \tsobj[pkg]{expl3}, or go over a loop using \tsobj{\pdfstrcmp}, or construct an if-then-else tower, etc. This implements a solution, based on \cite{stackexchage:switchcase}, which (besides being simple) has the advantage of being constant time: once the cases are set up, suffice a single (internal) if (\tsobj{\ifcsname}) to select the correct code to be executed. \begin{tsremark} The implementation creates a \tsobj{\csname} for each case, and it uses (at the end) the primitive \tsobj{\ifcsname} to select the correct case. \end{tsremark} \begin{tsremark} The coding is done using \tsobj[pkg]{expl3}, just for the sake of readability, in the package comments one can find an implementation using just \TeX\ primitives. \end{tsremark} \setnewcodekey {switch} { keywd2={newswitch,switch_new:Nn,addcase,switch_addcase:Nnn}, emph={TextCase,myCase}, emph2={CaseAstring}, codeprefix={}, resultprefix={} } \section{Commands} Two set of commands are created, one to be used in a \tsobj[pkg]{expl3} code régime, and another set to be used in a user document. \subsection{User Document ones} \begin{codedescribe}{\newswitch} \begin{codesyntax}% \tsobj{\newswitch} \tsmeta{switch} \tsargs[marg]{default-code} \end{codesyntax} It will create a new switch \tsobj[marg]{switch}, which will expects a single argument. In case the argument doesn't corresponds to any defined case, \tsobj[marg]{default-code} will be used. The resulting \tsobj[marg]{switch} command is expandable, if \tsobj[marg]{default-code} and \tsobj[marg]{case-code} (added by \tsobj{\addcase}) also are. This is just an alias for \tsobj{\switch_new:Nn} \end{codedescribe} \begin{tsremark} \verb|#1| can be used in \tsobj[marg]{default-code}. An error is raised if \tsobj[marg]{switch} is already defined. \end{tsremark} \begin{codedescribe}{\addcase} \begin{codesyntax}% \tsobj{\addcase} \tsmeta{switch} \tsargs[marg]{case,case-code} \end{codesyntax} It will add a \tsobj[marg]{case} to a previously defined \tsmeta{switch} and associates \tsobj[marg]{case-code} with it. \tsobj[marg]{case} will be fully expanded at definition time. Once defined one can call \tsverb[verb]{\switch{case}}, which will put said \tsobj[marg]{case-code} in the input stream. This is just an alias for \tsobj{\switch_addcase:Nnn}. \end{codedescribe} \subsubsection{Example} First we create a switch, and associate a few (or more) cases. Note the possibility of using an auxiliary (fully expandable) macro/command when defining the cases. \begin{codestore}[switch02] \def\CaseAstring{case-A} \newswitch \myCase {I~ don't~ know:~ #1\par} \addcase \myCase {\CaseAstring} {A~ was~ used\par} \addcase \myCase {case-B} {B~ was~ used\par} \end{codestore} \begin{codestore}[switch02] \def\somemacro{case-A} \def\someothermacro{case-X} If B, then \myCase{case-B} If A, then \myCase{case-A} If X, then \myCase{case-X} if somemacro: \myCase{\somemacro} if someothermacro: \myCase{\someothermacro} \end{codestore} \tscode*[switch]{switch02}[1] \tsexec{switch02}[1] To use the \tsobj[marg]{switch}, one just has to call it with \tsobj[marg]{case} as an argument. Note the possibility of using an auxiliary macro/command (which has to be fully expandable) as a \tsobj[marg]{case}. \tsdemo[switch]{switch02}[2] \subsection{Expl3 ones} \begin{codedescribe}{\switch_new:Nn} \begin{codesyntax}% \tsobj{\switch_new:Nn} \tsmeta{switch} \tsargs[marg]{default-code} \end{codesyntax} It will create a new switch \tsobj[marg]{switch}, which will expects a single, type n, argument. In case the argument doesn't corresponds to any defined case, \tsobj[marg]{default-code} will be used. The resulting \tsobj[marg]{switch} command is expandable, if \tsobj[marg]{default-code} and \tsobj[marg]{case-code} (added by \tsobj{\switch_addcase:Nnn}) also are. \end{codedescribe} \begin{tsremark} \verb|#1| can be used in \tsobj[marg]{default-code}. An error is raised if \tsobj[marg]{switch} is already defined. \end{tsremark} \begin{codedescribe}{\switch_addcase:Nnn} \begin{codesyntax}% \tsobj{\switch_addcase:Nnn} \tsmeta{switch} \tsargs[marg]{case,case-code} \end{codesyntax} It will add a \tsobj[marg]{case} to a previously defined \tsmeta{switch} and associates \tsobj[marg]{case-code} with it. \tsobj[marg]{case} will be fully expanded at definition time. Once defined one can call \tsverb[verb]{\switch{case}}, which will put said \tsobj[marg]{case-code} in the input stream. \end{codedescribe} \begin{codedescribe}[code,new=2025-05-13,EXP]{\switch_if_exist:NTF,\switch_if_case_exist:NnTF} \begin{codesyntax}% \tsobj{\switch_if_exist:NTF} \tsmeta{switch} \tsargs[marg]{if-true,if-false} \tsobj{\switch_if_case_exist:NnTF} \tsmeta{switch} \tsargs[marg]{case,if-true,if-false} \end{codesyntax} Tests if the \tsobj[marg]{switch}, or \tsobj[marg]{case}, are defined or not. It doesn't test if they are really a \tsobj[marg]{switch}/\tsobj[marg]{case}. \end{codedescribe} \begin{codedescribe}[code,new=2025-05-13]{\switch_undefine:N,\switch_case_undefine:Nn} \begin{codesyntax}% \tsobj{\switch_undefine:N} \tsmeta{switch} \tsobj{\switch_case_undefine:Nn} \tsmeta{switch} \tsargs[marg]{case} \end{codesyntax} Undefine the \tsobj[marg]{switch} and/or specific \tsobj[marg]{case}. Please note, when undefining a \tsobj[marg]{switch}, the \tsverb[verb]{\csname} associated with the cases aren't undefined (if needed, they have to be undefined one by one). \end{codedescribe} \subsubsection{Example} First we create a switch, and associate a few (or more) cases. Note the possibility of using an auxiliary (fully expandable) macro/command when defining the cases. \begin{codestore}[switch01] \ExplSyntaxOn \def\CaseAstring{case-A} \switch_new:Nn \TextCase {I~ don't~ know:~ #1\par} \switch_addcase:Nnn \TextCase {\CaseAstring} {A~ was~ used\par} \switch_addcase:Nnn \TextCase {case-B} {B~ was~ used\par} \ExplSyntaxOff \end{codestore} \begin{codestore}[switch01] \def\somemacro{case-A} \def\someothermacro{case-X} If B, then \TextCase{case-B} If A, then \TextCase{case-A} If X, then \TextCase{case-X} if somemacro: \TextCase{\somemacro} if someothermacro: \TextCase{\someothermacro} \end{codestore} \tscode*[switch]{switch01}[1] \tsexec{switch01}[1] To use the \tsobj[marg]{switch}, one just has to call it with \tsobj[marg]{case} as an argument. Note the possibility of using an auxiliary macro/command (which has to be fully expandable) as a \tsobj[marg]{case}. \tsdemo[switch]{switch01}[2] \section{Advanced Use} Since the resulting \tsobj[marg]{switch} is fully expandable (if the provided \tsobj[marg]{case-code}s also are), one can design the \tsobj[marg]{case-code}s to absorb one or more parameter/tokens. \begin{tsremark}[{\color{red}Careful:}] make sure that all \tsobj[marg]{case-code}s absorb the same number of parameters, to avoid ``leftovers'' or tricky errors. \end{tsremark} For instance, note the use of \tsobj{\@gobble} to absorb an unused parameter, or how \tsobj{\cmdY} is defined (with two parameters) then used with a ``fixed one''. The resulting command, \tsobj{\TCase}, absorbs 2 tokens/parameters: \begin{codestore}[switch03] \NewDocumentCommand \cmdX{m} {I got #1} \NewDocumentCommand \cmdY{mm} {Two: #1 and #2} \NewDocumentCommand \Astring{} {case-A} \makeatletter \newswitch \TCase {I~ don't~ know:~ #1 \@gobble} \makeatother \addcase \TCase {\Astring} {\cmdY{A~ given}} \addcase \TCase {case-B} {B~ was~ used. \cmdX} \end{codestore} \begin{codestore}[switch03] If B, then \TCase{case-B}{extra-B}\par If A, then \TCase{case-A}{extra-A}\par If X, then \TCase{case-X}{extra-X}\par \end{codestore} \tscode*[switch,emph={TCase},emph2={cmdX,cmdY,@gobble}]{switch03}[1] \tsexec{switch03}[1] \tsdemo[switch,emph={TCase},emph2={cmdX,cmdY,@gobble}]{switch03}[2] Needless to say, the same applies under \tsobj[pkg]{expl3}. \begin{codestore}[switch04] \ExplSyntaxOn \cs_new:Npn \__cmdX:n #1 {I~ got~ #1} \cs_new:Npn \__cmdY:nn #1#2 {Two:~ #1~ and~ #2} \tl_new:N \l__case_tl \tl_set:Nn \l__case_tl {case-A} \switch_new:Nn \TxCase {I~ don't~ know:~ #1 \use_none:n} \switch_addcase:Nnn \TxCase {\l__case_tl} {\__cmdY:nn{A~ given}} \switch_addcase:Nnn \TxCase {case-B} {B~ was~ used.~ \__cmdX:n} \ExplSyntaxOff \end{codestore} \begin{codestore}[switch04] If B, then \TxCase{case-B}{extra-B}\par If A, then \TxCase{case-A}{extra-A}\par If X, then \TxCase{case-X}{extra-X}\par \end{codestore} \tscode*[switch,emph={TxCase},emph2={cmdX,cmdY,use_none:n}]{switch04}[1] \tsexec{switch04}[1] \tsdemo[switch,emph={TxCase},emph2={cmdX,cmdY,@gobble}]{switch04}[2] \printbibliography \end{document}