summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/cals/cals/lltokens.dtx
blob: 35a1a8e905e02e82b6b601302bd8ecb0f46fc406 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
% \subsection{List list of tokens}
%
% Two-dimensional arrays of tokens, or lists of lists of tokens.
%
%
% Format of the list:
%
% \begin{verbatim}
% {...tokens1...}{...tokens2...}...{...tokensN...}
% \end{verbatim}
%
% Token manipulation should not belong to the ``cals'' package,
% and the macros from this section have the prefix |llt@|
% instead of |cals@|. Probably it is better to use some CTAN
% package, but initially the llt-code was small and simple, so
% I did not want dependencies, and now I do not want to replace
% working code with something new.
%
% In comments to these functions, a parameter of type \textit{token list}
% is a macro which will be expanded once to get the tokens, and
% \textit{list list} is a macro which stores the two-dimensional array.
%
% An example of use:
% \begin{verbatim}
% \def\aaa{aaa}
% \def\bbb{bbb}
% \def\ccc{ccc}
% \def\lst{}         % empty list
% \llt@cons\bbb\lst  % \lst -> "{bbb}"
% \llt@snoc\lst\ccc  % \lst -> "{bbb}{ccc}"
% \llt@cons\aaa\lst  % \lst -> "{aaa}{bbb}{ccc}"
% \llt@decons\lst    % \llt@car -> "aaa", \lst -> "{bbb}{ccc}"
% \llt@rot\lst       % \llt@car -> "bbb", \lst -> "{ccc}{bbb}"
% \end{verbatim}
%
%

%
% \begin{macro}{\llt@cons}
% Prepends the token list \#1 to the list list \#2.
% Corrupts the token registers 0 and~2.
%    \begin{macrocode}
\def\llt@cons#1#2{%
\toks0=\expandafter{#1}%
\toks2=\expandafter{#2}%
\edef#2{\noexpand{\the\toks0}\the\toks2 }%
}
%    \end{macrocode}
% \end{macro}

%
% \begin{macro}{\llt@snoc}
% Appends the token list \#2 to the list list \#1 (note the order
% of parameters).
% Macro corrupts the token registers 0 and 2.
%
%    \begin{macrocode}
\def\llt@snoc#1#2{%
\toks0=\expandafter{#1}%
\toks2=\expandafter{#2}%
\edef#1{\the\toks0 \noexpand{\the\toks2}}%
}
%    \end{macrocode}
% \end{macro}

%
% \begin{macro}{\llt@car}
% A token list, set as a side-effect of the list deconstruction
% and rotation functions.
% \end{macro}

%
% \begin{macro}{\llt@decons}
% List deconstruction. The first item is removed from the list list \#1
% and its tokens are put to the token list |\llt@car|.
% Corrupts the token register 0.
% Undefined behaviour if the list list has no items.
%
% The actual work happens on the |\expandafter| line.
% It's hard to explain, let me show the macro expansion,
% I hope it's self-explaining.
%
% \begin{verbatim}
% \expandafter\llt@decons@open\lst}      -->
% \llt@decons@open{aaa}{bbb}{ccc}{ddd}}  -->
% \def\llt@car{aaa} \toks0=\llt@opengroup {bbb}{ccc}{ddd}}  -->
% \def\llt@car{aaa} \toks0={{bbb}{ccc}{ddd}}
% \end{verbatim}
% 
% Why I use |\let\llt@opengroup={| inside the definition?
% Only to balance the number of opening and closing brackets.
% Otherwise TeX will not compile the definition.
%
% Initially I tried to use the following helper:
%
% \begin{verbatim}
% \def\decons@helper#1#2\relax{%
%   \def\llt@car{#1}%
%   \def\list{#2}}
% \end{verbatim}
%
% If a call is |\decons@helper{aaa}{bbb}{ccc}\relax| then
% all is ok, the helper gets: \#1 is |aaa| and \#2 is
% |{bbb}{ccc}|.
%
% Unfortunately, if the list has two items and the call is
% |\decons@helper{aaa}{bbb}}\relax|, then the helper gets:
% \#1 is |aaa| and \#2 is |bbb| instead of |{bbb}|.
% The grouping tokens are lost, and we can't detect it.
%
%    \begin{macrocode}
\def\llt@decons@open#1{%
\def\llt@car{#1}%
\toks0=\llt@opengroup
}

\def\llt@decons#1{%
\let\llt@opengroup={%
\expandafter\llt@decons@open#1}%
\edef#1{\the\toks0}%
}
%    \end{macrocode}
% \end{macro}

%
% \begin{macro}{\llt@rot}
% Rotates the list list \#1. The first item becomes the last. Also,
% its tokens are saved to token list |\llt@car|.
% The second item becomes the first item, the third the second etc.
% Corrupts the token registers 0 and 2.
%
%    \begin{macrocode}
\def\llt@rot#1{%
\ifx#1\empty
\let\llt@car=\relax
\else
\llt@decons#1%
\llt@snoc#1\llt@car%
\fi
}
%    \end{macrocode}
% \end{macro}

%
% \begin{macro}{\llt@desnoc}
% Very unefficient list deconstruction. The last item is removed
% from the list list \#1 % and its tokens are put to the token
% list |\llt@car|. Corrupts the token registers 0 and 2.
% Undefined behaviour if the list list has no items.
%
% |\llt@desnocII| is used to hide |\if| from the loop.
%    \begin{macrocode}
\def\llt@desnocII#1{
\ifx\empty#1%
\let\llt@tmp=n%
\else
\llt@snoc{\llt@newlist}{\llt@car}%
\let\llt@tmp=y%
\fi
}

\def\llt@desnoc#1{%
\def\llt@newlist{}%
\loop
\llt@decons{#1}%
\llt@desnocII{#1}%
\if y\llt@tmp \repeat
\let#1=\llt@newlist}
%    \end{macrocode}
% \end{macro}