summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/yquant/yquant-env.tex
blob: 16c3598af38f9676fe105db28cd8ea401a4ea019 (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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
\newif\ifyquant@env@lazy

\protected\def\yquant@envunstar{%
   \yquant@env@lazyfalse%
   \yquant@env@begin%
}

\protected\def\yquant@envstar{%
   \yquant@env@lazytrue%
   \yquant@env@begin%
}

\protected\def\yquant@env@begin{%
   % We check for an optional argument, but if it is in a new line, we don't take it - it
   % might well be the square brace of an argument. Temporary change newlines to ordinary
   % characters.
   \catcode`\^^M=12 %
   \yquant@futurenonspacelet\yquant@env@begin@next\yquant@env@begin@checkarg%
}

{\catcode`\^^M=12 \global\let\yquant@env@linebreak=^^M}

\protected\def\yquant@env@begin@checkarg{%
   \catcode`\^^M=5 %
   \ifx\yquant@env@begin@next[%
      \expandafter\yquant@env@begin@arg%
   \else%
      \ifx\yquant@env@begin@next\yquant@env@linebreak%
         % In this case we don't really want to inject the wrong-catcode linebreak back,
         % which would produce an error.
         \afterassignment\yquant@env@begin@noarg%
         \expandafter\expandafter\expandafter\let%
         \expandafter\expandafter\expandafter\@eattoken%
         % since ^^M is an ordinary character, no need for "= ".
      \else%
         \expandafter\expandafter\expandafter\yquant@env@begin@noarg%
      \fi%
   \fi%
}

\def\yquant@env@begin@noarg{%
   \yquant@env@begin@arg[]%
}

\long\protected\def\yquant@env@begin@arg[#1]{%
   \begingroup%
      \advance\yquant@env by 1 %
      \edef\yquant@prefix{yquant@env\the\yquant@env @}%
      \let\yquant=\yquant@env@scan%
      \yquant@lang@reset@attrs%
      \csgdef{\yquant@prefix registers}{0}%
      \global\cslet{\yquant@prefix draw}\relax%
      \global\cslet{\yquant@prefix outputs}\relax%
      \csxdef{\yquant@prefix cleanup}{%
         \expandafter\noexpand\csname\yquant@prefix registers\endcsname%
         \expandafter\noexpand\csname\yquant@prefix draw\endcsname%
         \expandafter\noexpand\csname\yquant@prefix outputs\endcsname%
         \expandafter\noexpand\csname\yquant@prefix cleanup\endcsname%
      }%
      \ifnum\yquant@env=1 %
         \yquant@env@substikz%
      \fi%
      \scope[{/yquant/.cd, #1, /tikz/.cd, /yquant/every circuit}]%
}
\newif\ifyquantdebug
\protected\def\yquant@env@end{%
         \letcs\yquant@env@end@registers{\yquant@prefix registers}%
         \ifnum\yquant@env@end@registers>0 %
            % draw all wires
            \yquant@register@get@maxxrange\yquant@env@end@xpos{1}{\yquant@env@end@registers}%
            % to have a symmetric situation, we extend again one separation at the end
            \csxappto{\yquant@prefix draw}{%
               \def\noexpand\yquant@env@end@xpos{%
                  \the\dimexpr\yquant@env@end@xpos+\yquant@config@operator@sep\relax%
               }%
               \yquant@circuit@endwires{\yquant@env@end@registers}%
            }
            % also calculate the true y positions
            \dimen0=0pt %
            \dimen2=0pt %
            \dimen4=\yquant@config@register@sep %
            \yquant@for \i := 1 to \yquant@env@end@registers {%
               % we do not care if the wire is present for the y position
               \dimen2=.5\dimexpr\yquant@register@get@height\i\relax%
               \advance\dimen0 by \dimen2\relax%
               % top-to-bottom means negative coordinates in pgf
               \yquant@register@set@y\i{-\the\dimen0}%
               \advance\dimen0 by \dimen2\relax%
               \advance\dimen0 by \dimen4\relax%
            }%
            \csname\yquant@prefix outputs\endcsname%
         \fi%
      \endscope%
      % Now we actually carry out the tikz commands which were previously stored in the draw command. But before this, we get rid of all \yquant@env@scan calls and also restore the scope command, since this would add itself once again. And get@y needs to expand.
      \let\path=\tikz@command@path%
      \let\tikz@lib@scope@check=\yquant@env@substikz@scopecheck%
      \let\tikz@scope@opt=\yquant@env@substikz@scope%
      \let\endtikz@scope@env=\yquant@env@substikz@endscope%
      \let\endscope=\endtikz@scope@env%
      \let\stopscope=\endscope%
      \yquant@register@get@y@@expandable%
      \ifyquantdebug%
         \csshow{\yquant@prefix draw}%
      \fi%
      \csname\yquant@prefix draw\endcsname%
      \expandafter\expandafter\expandafter\yquant@cleanup\csname\yquant@prefix cleanup\endcsname|%
   \endgroup%
}

\tikzaddtikzonlycommandshortcutlet\yquant\yquant@envunstar
\expandafter\tikzaddtikzonlycommandshortcutlet\csname yquant*\endcsname\yquant@envstar
\tikzaddtikzonlycommandshortcutlet\endyquant\yquant@env@end
\expandafter\tikzaddtikzonlycommandshortcutlet\csname endyquant*\endcsname\yquant@env@end

\protected\def\yquantset{%
   \pgfqkeys{/yquant}%
}
\let\yquant@set=\yquantset%

% private yquant-language related helpers
% In order to allow nested environments and also grouping (without the need to smuggle definitions out of the groups whenever necessary), we count the number of nested environments.
\newcount\yquant@env

\def\yquant@env@substikz@finish{%
   % Rendering pipeline
   \endgroup%
   \global\pgflinewidth=\tikzscope@linewidth\relax%
   \tikz@path@do@at@end%
}

% first undoes the substikz commands, next turns the \path command into a virtual one that does not produce any output.
\protected\def\yquant@env@virtualize@path{%
   \yquant@register@get@y@@expandable%
   \let\path=\tikz@command@path%
   \let\tikz@finish=\yquant@env@substikz@finish%
   \let\tikz@lib@scope@check=\yquant@env@substikz@scopecheck%
}

% substitute the tikz commands (defined in \tikz@installcommands) so that they can be arbitrarily interleaved with yquant code. We patch \path, \scope, \endscope, \stopscope, their internal complements, and also patch \yquantset.
\protected\def\yquant@env@substikz{%
   % \tikz@path@do@at@end is called after a path. Hence, it is an ideal candidate to re-invoke \yquant@env@scan. However, it is by default defined to be \tikz@lib@scope@check, and we need this definition for the scopes library to work correctly. But since \tikz@lib@scope@check is also called after a scope and the end of a scope, this is even better. Yet, we need to check whether the scopes library is present or not.
   \let\yquant@env@substikz@scopecheck=\tikz@lib@scope@check%
   \ifx\tikz@lib@scope@check\pgfutil@empty%
      % no, it is not. This is simple.
      \let\tikz@lib@scope@check=\yquant@env@scan%
   \else%
      % yes, it is. Call it after the special behavior is done.
      \patchcmd\tikz@lib@scope@check{{}}{\yquant@env@scan}\relax{%
         \PackageWarning{yquant.sty}{Patching \string\tikz@lib@scope@check\space failed; you must invoke \string\yquant\space manually after every tikz command to switch back to yquant code.}%
      }
   \fi%
   % We not only need to re-invoke yquant after the tikz command, but we must also make sure that the tikz command is not actually drawn now, but at the end. However, what happens if some macros are used within the command? Here, we choose to expand the macros to the values they have _now_, but protected (which should prevent bad things for formatting commands). If you find this to be an issue, please report.
   \def\path##1;{%
      \protected@csxappto{\yquant@prefix draw}{%
         \noexpand\path##1;%
      }%
      \yquant%
   }%
   % no need for \scoped, because it internally calls \scope.
   % We need to hack into \scope, but this is a bit tricky due to its argument handling. In order to get all optional arguments, including the possible animations library, correct, we change \tikz@scope@opt.
   \let\yquant@env@substikz@scope=\tikz@scope@opt%
   \def\tikz@scope@opt[##1]{%
      \protected@csxappto{\yquant@prefix draw}{%
         \noexpand\tikz@scope@env[{##1}]%
      }%
      \yquant@env@substikz@scope[{##1}]%
   }%
   \let\yquant@env@substikz@endscope=\endtikz@scope@env%
   \def\endtikz@scope@env{%
      \csgappto{\yquant@prefix draw}{%
         \yquant@env@substikz@endscope%
      }%
      \yquant@env@substikz@endscope%
   }%
   \let\endscope=\endtikz@scope@env%
   \let\stopscope=\endscope%
   % We define \yquantset as a pgfkeys-like macro. Anything else would deteriorate performance badly, as \pgfkeys, \pgfqkeys, or \tikzset are used a lot internally.
   \protected\def\yquantset##1{%
      \protected@csxappto{\yquant@prefix draw}{%
         \noexpand\pgfqkeys{/yquant}{##1}%
      }%
      \pgfqkeys{/yquant}{##1}%
      \yquant@env@scan%
   }%
}

% Scan until the next non-space token is found and execute it as a csname
\def\yquant@env@scan{%
   \begingroup%
      \yquant@env@contscan%
}

\protected\def\yquant@env@contscan{%
   \yquant@futurenonspacelet\yquant@env@nextchar\yquant@env@check%
}

\def\yquant@env@rescan{%
   \endgroup%
   \yquant@env@scan%
}

\protected\def\yquant@env@check{%
   \let\next=\relax%
   % Here we assume standard catcodes for A and [, but our language specification also requires this implicitly.
   \ifx\yquant@env@nextchar[%
      \let\next=\yquant@langhelper@check@attrs%
   \else%
      \ifcat\noexpand\yquant@env@nextchar A% letter
         \let\next=\yquant@langhelper@check@name%
      \else%
         \ifcat\noexpand\yquant@env@nextchar\bgroup%
            \endgroup%
            \let\next=\yquant@env@opengroup%
         \else%
            \ifcat\noexpand\yquant@env@nextchar\egroup%
               \endgroup%
               \let\next=\yquant@env@closegroup%
            \else%
               \ifx\yquant@env@nextchar\par%
                  \let\next=\yquant@env@gobblepar%
               \else%
                  \ifcat\noexpand\yquant@env@nextchar\relax%
                     \endgroup%
                     \let\next=\relax%
                  \else%
                     \PackageError{yquant.sty}%
                        {Invalid yquant syntax: `\meaning\yquant@env@nextchar'}%
                        {Adhere to the specs!}%
                  \fi%
               \fi%
            \fi%
         \fi%
      \fi%
   \fi%
   \next%
}

\protected\def\yquant@env@opengroup{%
   \afterassignment\yquant@env@opengroup@aux%
   \let\@eattoken= %
}

\def\yquant@env@opengroup@aux{%
   \bgroup%
      \csgappto{\yquant@prefix draw}{\begingroup}%
      \yquant@env@scan%
}

\def\yquant@env@closegroup{%
   \csgappto{\yquant@prefix draw}{\endgroup}%
   \aftergroup\yquant@env@scan%
}

\def\yquant@env@gobblepar{%
   \afterassignment\yquant@env@contscan%
   \let\@eattoken= %
}