mult-aux.mkxl /size: 56 Kb    last modification: 2024-01-16 09:02
1%D \module
2%D   [       file=mult-aux,
3%D        version=2010.08.2,
4%D          title=\CONTEXT\ Multilingual Macros,
5%D       subtitle=Helpers,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14%D A generalization of \MKIV-like inheritance. Just something to play with
15%D (interface might change). The code here evolved in an email exchange between me
16%D and Wolgang Schuster.
17
18%D We use constant definitions here because we don't need to expand the keywords
19%D which saves a little on the stack (read: memory access). The gain in performance
20%D is normally not noticeable unless one has plenty of parameter checking, which
21%D can happen in some scenarios. Even then the gain is only there when one has
22%D thousands of runs on e.g. virtual platforms.
23
24\writestatus{loading}{ConTeXt Multilingual Macros / Helpers}
25
26\registerctxluafile{mult-aux}{}
27
28\unprotect
29
30\immutable\cdef\??empty{\tocharacter25}  \immutable\letvalue{\tocharacter25}\empty % hex 19
31
32% \edef\s!parent{\tocharacter29} % inlining  is ugly, a tiny bit faster, but neglectable on a run
33
34%D \starttyping
35%D \unprotect
36%D     \def\????aa{@@@@aa}
37%D
38%D     \installparameterhandler   \????aa {whatever}
39%D     \installsetuphandler       \????aa {whatever}
40%D     \installdefinehandler      \????aa {whatever} \????aa % #3 == defaultroot
41%D     \installfontandcolorhandler\????aa {whatever}
42%D
43%D   % \installcommandhandler     \????aa {whatever} \????aa
44%D \protect
45%D
46%D % \whateverparameter \c!test
47%D % \whateverparameterhash \c!test
48%D % \namedwhateverparameter \mycurrentwhatever \c!test
49%D % \usewhateverstyleandcolor \c!style \c!color
50%D % \everydefinewhatever (sets \currentwhatever)
51%D % \everypresetwhatever (can be used to reset parameters as we can redefine)
52%D % \everysetupwhatever (sets \currentwhatever)
53%D
54%D \starttext
55%D     \definewhatever[first] \definewhatever[second][first]
56%D                                           test: \def\currentwhatever{first}  \whateverparameter{method} \par
57%D     \setupwhatever        [method=unset]  test: \def\currentwhatever{first}  \whateverparameter{method} \par
58%D     \setupwhatever[first] [method=first]  test: \def\currentwhatever{first}  \whateverparameter{method} \par
59%D                                           test: \def\currentwhatever{second} \whateverparameter{method} \par
60%D     \setupwhatever[second][method=second] test: \def\currentwhatever{second} \whateverparameter{method} \par
61%D \stoptext
62%D \stoptyping
63
64% problem: every* could clash
65%
66% There can be less {} in the following definitions if we assume \??aa and \c!somecs
67%
68% watch the push/pop and predefinition of current .. this is needed for nested
69% definitions and overloaded defines using the predefined one
70
71% todo: add (relaxed) postsetup and postdefine hooks, just after the everys
72
73%D Start of experimental code: especially tables can have many assignments and
74%D although most time is spent in the typesetting anyway, we can squeeze out a
75%D little bit. Of course having 500 rows of 50 columns each with some setting does
76%D not happen that often. One should keep in mind that in the average document
77%D having some 500 assignments is no exception but there we're talking of
78%D neglectable runtime for them. Of course in the definitions below there is no real
79%D gain, only in the generated \setup* commands. Another situation with many
80%D assignments is \XML\ where we can pass attributes and normally don't do testing
81%D of them making sense.
82%
83% \testfeatureonce{100000}{\getparameters[bla][a=111,b=222,c=333]}% 1.669s
84% \testfeatureonce{100000}{\mult_interfaces_get_parameters{bla} [a=111,b=222,c=333]}% 1.529s
85% \testfeatureonce{100000}{\def\m_mult_interfaces_namespace{bla}\mult_interfaces_get_parameters_indeed[a=111,b=222,c=333]}% 1.466s
86
87% KEEP THIS:
88%
89% \lettonothing\m_mult_interfaces_namespace
90%
91% \def\mult_interfaces_get_parameters#1[#2%
92%   {\if\noexpand#2]%
93%      \expandafter\gobbleoneargument
94%    \else
95%      \def\m_mult_interfaces_namespace{#1}%
96%      \expandafter\mult_interfaces_get_parameters_indeed
97%    \fi#2}
98%
99% \def\mult_interfaces_get_parameters_indeed#1]% namespace already set
100%   {\mult_interfaces_get_parameters_item#1,],^^^^0004}
101%
102% \def\mult_interfaces_get_parameters_item#1,#2% #2 takes space before ,
103%   {\if,#1,% dirty trick for testing #1=empty
104%      \expandafter\mult_interfaces_get_parameters_item
105%    \orelse\if]#1%
106%      \expandafter\gobbleoneargument
107%    \else
108%      \mult_interfaces_get_parameters_assign#1==\empty^^^^0004%
109%    % \expandafter\mult_interfaces_get_parameters_item % saves skipping when at end
110%    \fi#2}
111%
112% \def\mult_interfaces_get_parameters_error#1#2% #3%
113%   {\mult_interfaces_get_parameters_error_indeed{#1}{#2}%
114%    \gobbleoneargument}
115%
116% \def\mult_interfaces_get_parameters_error_indeed#1#2%
117%   {\showassignerror{#2}{\the\inputlineno\space(#1)}}
118%
119% \def\mult_interfaces_get_parameters_assign#1=#2=#3#0^^^^0004%
120%   {\ifx\empty#1\empty
121%      \expandafter\mult_interfaces_get_parameters_error
122%    \orelse\ifx#3\empty
123%      \expandafter\mult_interfaces_get_parameters_error
124%    \else
125%      \expandafter\mult_interfaces_adef % assignment def
126%    \fi
127%    \m_mult_interfaces_namespace{#1}{#2}%
128%    \doubleexpandafter\mult_interfaces_get_parameters_item}
129%
130% \startinterface english
131%
132%     % some 10% faster
133%
134%     \let\mult_interfaces_get_parameters_error\undefined
135%
136%     \def\mult_interfaces_get_parameters_error_one#0\csname#2#3\endcsname#0%
137%       {\mult_interfaces_get_parameters_error_indeed{#2}{#3}\iftrue}
138%
139%     \def\mult_interfaces_get_parameters_error_two#0\csname#2#3\endcsname#0%
140%       {\mult_interfaces_get_parameters_error_indeed{#2}{#3}}
141%
142%     \def\mult_interfaces_get_parameters_assign#1=#2=#3#0^^^^0004%
143%       {\ifx\empty#1\empty
144%          \mult_interfaces_get_parameters_error_one
145%        \orelse\ifx#3\empty
146%          \mult_interfaces_get_parameters_error_two
147%        \else
148%          \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
149%        \fi
150%        \doubleexpandafter\mult_interfaces_get_parameters_item}
151%
152% \stopinterface
153%
154% \newif\ifassignment
155%
156% \def\mult_check_for_assignment_indeed#0=#2#0^^^^0004%
157%   {\if#2^^^^0003\assignmentfalse\else\assignmenttrue\fi}
158%
159% \def\mult_check_for_assignment_indeed_begin_#0=#2#0^^^^0004%
160%   {\if#2^^^^0003}
161%
162% \def\mult_check_for_assignment#1%
163%   {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
164%
165% % End of experimental code.
166
167%D We keep the above as reference, but from now on experiment with the following
168%D implementation. In principle this one is faster, but because normally we don't
169%D have that many assignments it doesn't get noticed. For instance, the \LUAMETATEX\
170%D manual does less than 6000 assignments and the payoff starts around a tenfold of
171%D that. But \unknown\ it's less tracing, so that's another benefit.
172
173%D Watch out: we accept that a \[k=v,,k=v] will generate a case where a key can become
174%D a comma and trigger a warning but we intercept that elsewhere. The alternative is
175%D to skip to the comma first which takes more time.
176
177\lettonothing\m_mult_interfaces_namespace
178
179% \def\mult_interfaces_get_parameters#1[%
180%   {\def\m_mult_interfaces_namespace{#1}%
181%    \futureexpandis]\gobbleoneargument\mult_interfaces_get_parameters_indeed}
182%
183% \def\mult_interfaces_get_parameters_indeed#1]%
184%   {\mult_interfaces_get_parameters_item#1\ignorearguments\ignorearguments}
185%
186% \def\mult_interfaces_get_parameters_item#*#1,%
187%   {\ifarguments
188%    \else
189%      \mult_interfaces_get_parameters_item_okay#1,\ignorearguments
190%      \expandafter\mult_interfaces_get_parameters_item
191%    \fi}
192%
193% \def\mult_interfaces_get_parameters_item_okay#1=#2,%
194%   {\ifarguments
195%      % done
196%    \or
197%      \mult_interfaces_get_parameters_item_error
198%    \else
199%      \mult_interfaces_adef\m_mult_interfaces_namespace{#1}{#2}%
200%    \fi}
201%
202% \def\mult_interfaces_get_parameters_item_error#-#-#-#1#2%
203%   {\if,#2\else\mult_interfaces_get_parameters_error_indeed{#1}{#2}\fi}
204%
205% \startinterface english
206%
207%     \def\mult_interfaces_get_parameters_item_okay#1=#2,%
208%       {\ifarguments
209%          % done
210%        \or
211%          \mult_interfaces_get_parameters_item_error
212%        \else
213%          \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
214%        \fi}
215%
216%     \def\mult_interfaces_get_parameters_item_error#-\defcsname#1#2\endcsname#-%
217%       {\if,#2\else\mult_interfaces_get_parameters_error_indeed{#1}{#2}\fi}
218%
219% \stopinterface
220
221% cheap with no checking
222%
223% \def\mult_interfaces_get_parameters#1[#S#2]%
224%   {\cdef\m_mult_interfaces_namespace{#1}%
225%    \mult_interfaces_get_parameters_item_okay#2\ignorearguments\ignorearguments}
226%
227% \tolerant\def\mult_interfaces_get_parameters_item_okay#*#1=#S#2,#M,%
228%   {\ifparameter#2\or
229%      \ifcsname\k!prefix!#1\endcsname
230%        \defcsname\m_mult_interfaces_namespace\lastnamedcs\endcsname{#2}%
231%      \else
232%        \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
233%      \fi
234%    \orelse\ifparameter#1\or
235%      \ifcsname\k!prefix!#1\endcsname
236%        \letcsname\m_mult_interfaces_namespace\lastnamedcs\endcsname\empty
237%      \else
238%        \letcsname\m_mult_interfaces_namespace#1\endcsname\empty
239%      \fi
240%    \else
241%      \expandafter\gobbleoneargument
242%    \fi
243%    \mult_interfaces_get_parameters_item_okay}
244%
245% \startinterface english
246%
247%    \tolerant\def\mult_interfaces_get_parameters_item_okay#*#1=#S#2,#M,%
248%      {\ifparameter#2\or
249%         % k=v
250%         \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
251%       \orelse\ifparameter#1\or
252%         % k=
253%         \letcsname\m_mult_interfaces_namespace#1\endcsname\empty
254%       \else
255%         \expandafter\gobbleoneargument
256%       \fi
257%       \mult_interfaces_get_parameters_item_okay}
258%
259% \stopinterface
260
261%D Still not nice
262
263% \def\mult_interfaces_get_parameters#1[%
264%   {\cdef\m_mult_interfaces_namespace{#1}%
265%    \futureexpandis]\gobbleoneargument\mult_interfaces_get_parameters_indeed}
266%
267% \def\mult_interfaces_get_parameters_indeed#S#1]%
268%   {\mult_interfaces_get_parameters_item#1\ignorearguments\ignorearguments}
269
270\def\mult_interfaces_get_parameters#1[#S#2]%
271  {\cdef\m_mult_interfaces_namespace{#1}%
272   \mult_interfaces_get_parameters_item#2\ignorearguments\ignorearguments}
273
274% \def\mult_interfaces_get_parameters_item#*#S#1,%
275%   {\ifarguments
276%    \else
277%      \mult_interfaces_get_parameters_item_okay#1,\ignorearguments
278%      \expandafter\mult_interfaces_get_parameters_item
279%    \fi}
280
281\def\mult_interfaces_get_parameters_item#*#S#1,%
282  {\ifarguments
283     \expandafter\gobbleoneargument
284   \else
285     \mult_interfaces_get_parameters_item_okay#1,\ignorearguments
286   \fi
287   \mult_interfaces_get_parameters_item}
288
289% \tolerant\def\mult_interfaces_get_parameters_item_okay#1=#S#2,%
290%   {\ifarguments
291%      % done
292%    \or
293%      \mult_interfaces_get_parameters_item_error
294%    \else
295%      \mult_interfaces_adef\m_mult_interfaces_namespace{#1}{#2}%
296%    \fi}
297
298% \tolerant\def\mult_interfaces_get_parameters_item_okay#1=#S#2,%
299%   {\ifarguments
300%      % done
301%    \or
302%      \mult_interfaces_get_parameters_item_error{#1}%
303%    \orelse\ifcsname\k!prefix!#1\endcsname
304%      \defcsname\m_mult_interfaces_namespace\lastnamedcs\endcsname{#2}%
305%    \else
306%      \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
307%    \fi}
308
309\tolerant\def\mult_interfaces_get_parameters_item_okay#1=#S#2,%
310  {\ifarguments
311     % done
312   \or
313     \mult_interfaces_get_parameters_item_error{#1}%
314   \or
315     \defcsname
316       \m_mult_interfaces_namespace
317       \ifcsname\k!prefix!#1\endcsname\lastnamedcs\else#1\fi
318     \endcsname{#2}%
319   \fi}
320
321\def\mult_interfaces_get_parameters_item_error#1%
322  {\if,#1\else\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#1}\fi}
323
324\startinterface english
325
326    \def\mult_interfaces_get_parameters_item_okay#1=#S#2,%
327      {\ifarguments
328         % done
329       \or
330         \mult_interfaces_get_parameters_item_error{#1}%
331       % \mult_interfaces_get_parameters_item_error
332       % \if,#1\else\mult_interfaces_get_parameters_item_error\fi
333       \else
334         \defcsname\m_mult_interfaces_namespace#1\endcsname{#2}%
335       \fi}
336
337  % \def\mult_interfaces_get_parameters_item_error#-\defcsname#1#2\endcsname#-%
338  %   {\if,#2\else\mult_interfaces_get_parameters_error_indeed{#1}{#2}\fi}
339
340  % \def\mult_interfaces_get_parameters_item_error#-\defcsname#-#1\endcsname#-%
341  %   {\if,#1\else\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#1}\fi}
342
343    \def\mult_interfaces_get_parameters_item_error#1%
344      {\if,#1\else\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#1}\fi}
345
346  % \def\mult_interfaces_get_parameters_item_error
347  %    {\mult_interfaces_get_parameters_error_indeed
348  %       {\m_mult_interfaces_namespace}
349  %       {\expandparameter\plusthree}}
350
351\stopinterface
352
353% % No longer used:
354%
355% \def\mult_check_for_assignment_indeed#-=#1#-^^^^0004%
356%   {\if#1^^^^0003\assignmentfalse\else\assignmenttrue\fi}
357%
358% \def\mult_check_for_assignment_indeed_begin_#-=#1#-^^^^0004%
359%   {\if#1^^^^0003}
360%
361% \def\mult_check_for_assignment#1%
362%   {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=^^^^0003^^^^0003^^^^0004}
363
364%D Beware, zero arguments is an assignment!
365
366\def\mult_aux_no_assignment_indeed#1=#2]{\ifcase\ifarguments\plusone\or\zerocount\else\plusone\fi}
367\def\mult_aux_no_assignment#1]{\mult_aux_no_assignment_indeed#1\ignorearguments\relax}
368
369%D This can give wrong results when we pass e.g. \type{\c!format}, so either we need
370%D to use the \type {\k!} ones, but these are not defined in the english interface
371%D so from now on we assume that the low level ones are used with the symbolic names
372%D and that only the high level setup commands are used with language specific
373%D interfaces.
374
375% \startinterface english
376    \protected\def\mult_interfaces_let #1#2{\letcsname#1#2\endcsname}
377    \protected\def\mult_interfaces_lete#1#2{\letcsname#1#2\endcsname\empty}
378    \protected\def\mult_interfaces_def #1#2{\defcsname#1#2\endcsname}
379    \protected\def\mult_interfaces_edef#1#2{\edefcsname#1#2\endcsname}
380    \protected\def\mult_interfaces_gdef#1#2{\gdefcsname#1#2\endcsname}
381    \protected\def\mult_interfaces_xdef#1#2{\xdefcsname#1#2\endcsname}
382% \stopinterface
383
384%D Do, we only interface the assignment definition:
385
386\protected\def\mult_interfaces_adef#1#2{\defcsname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname}
387
388\startinterface english
389    \protected\def\mult_interfaces_adef#1#2{\defcsname#1#2\endcsname}
390\stopinterface
391
392% the commented detokenized variant that backtracks ... needs testing usage first
393%
394% \let\whatever\relax
395%
396% \definetest[oeps][bagger=\whatever]
397%
398% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{bagger}}\meaning\hans\par
399% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{reggab}}\meaning\hans\par
400%
401% slower: \def#3##1{\csname\ifcsname#1#2:##1\endcsname\expandafter\csstring\lastnamedcs\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
402
403%D pre-expansion can be a bit faster but handly any effect on a normal run so let's
404%D go for saving some memory.
405
406%def\mult_interfaces_detokenize{\expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter}
407
408\protected\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8#9%
409  {\frozen\def#3##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}%
410   \frozen\def#4##1##2{\ifcsname##1:##2\endcsname##1:##2\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}%
411   \frozen\edef#5##1##2{\noexpand\ifrelax##1\??empty\noexpand\else\noexpand#4##1{##2}\noexpand\fi}% is {} needed around ##1 ?
412   \frozen\def#6##1##2{\csname\ifcsname#1##1:##2\endcsname#1##1:##2\else\expandafter#5\csname#1##1:\s!parent\endcsname{##2}\fi\endcsname}%
413  %\frozen\def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack
414   \frozen\def#7##1{\expandafter\detokened\csname#1#2:##1\endcsname}% always root, no backtrack
415   \frozen\def#8##1{\begincsname#1#2:##1\endcsname}%
416   % TODO
417   \frozen\def#9##1##2{\expandafter\let\expandafter##1\csname\ifcsname#1#2:##2\endcsname#1#2:##2\else\expandafter#5\csname#1#2:\s!parent\endcsname{##2}\fi\endcsname}}
418
419\permanent\protected\def\installparameterhandler#1#2%
420  {\mutable\constant\letcsname current#2\endcsname\empty
421   \normalexpanded
422     {\mult_interfaces_install_parameter_handler
423        {\noexpand#1}% \??aa
424        \expandafter\noexpand\csname current#2\endcsname
425        \expandafter\noexpand\csname #2parameter\endcsname
426        \expandafter\noexpand\csname do#2parameter\endcsname        % or: #2_parameter
427        \expandafter\noexpand\csname do#2parentparameter\endcsname  % or: #2_parent_parameter
428        \expandafter\noexpand\csname named#2parameter\endcsname
429        \expandafter\noexpand\csname detokenized#2parameter\endcsname
430        \expandafter\noexpand\csname direct#2parameter\endcsname
431        \expandafter\noexpand\csname letfrom#2parameter\endcsname}} % strict#2parameter is gone
432
433\protected\def\mult_interfaces_install_root_parameter_handler#1#2#3%
434 %{\frozen\def#2##1{\detokenize\expandafter\expandafter\expandafter{\csname#1:##1\endcsname}}% always root
435  {\frozen\def#2##1{\expandafter\detokened\csname#1:##1\endcsname}% always root
436   \frozen\def#3##1{\begincsname#1:##1\endcsname}}
437
438\permanent\protected\def\installrootparameterhandler#1#2%
439  {\normalexpanded
440     {\mult_interfaces_install_root_parameter_handler
441        {\noexpand#1}% \??aa
442        \expandafter\noexpand\csname detokenizedroot#2parameter\endcsname
443        \expandafter\noexpand\csname root#2parameter\endcsname}}
444
445\protected\def\mult_interfaces_install_parameter_hash_handler#1#2#3#4#5#6#7#8#9%
446  {\frozen\def#3##1{#1#4{#1#2}{##1}:}% leading #1 was missing .. is this one used?
447   \frozen\def#4##1##2{\ifcsname##1:##2\endcsname##1\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}%
448   \frozen\def#5##1##2{\ifrelax##1\else#4##1{##2}\fi}%
449   \frozen\def#6{#1#2:}%
450   \frozen\def#7##1{#1##1:}%
451   \frozen\def#8{\ifempty#2\orelse\ifcsname#1#2:\s!parent\endcsname\else\letcsname#1#2:\s!parent\endcsname#1\fi}%
452   \frozen\protected\def#9##1{\edefcsname#1##1:\s!parent\endcsname{#1#2}}}
453
454\permanent\protected\def\installparameterhashhandler#1#2%
455  {\mutable\letcsname current#2\endcsname\empty
456   \immutable\letcsname#2namespace\endcsname#1%
457   \normalexpanded
458     {\mult_interfaces_install_parameter_hash_handler
459        {\noexpand#1}% \??aa
460        \expandafter\noexpand\csname current#2\endcsname
461        \expandafter\noexpand\csname #2parameterhash\endcsname
462        \expandafter\noexpand\csname do#2parameterhash\endcsname         % or : #2_parameter_hash
463        \expandafter\noexpand\csname do#2parentparameterhash\endcsname   % or : #2_parent_parameter_hash
464        \expandafter\noexpand\csname current#2hash\endcsname
465        \expandafter\noexpand\csname named#2hash\endcsname
466        \expandafter\noexpand\csname check#2parent\endcsname
467        \expandafter\noexpand\csname chaintocurrent#2\endcsname}}
468
469%D In \MKIV\ we can probably use the english variant for all other languages too.
470
471% todo: inline the def/let
472
473% \startinterface english
474    \protected\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6%
475      {\frozen\protected\def#3##1{\defcsname#1#2:##1\endcsname}%        ##1 {##2} (braces are mandate)
476       \frozen\protected\def#4##1{\edefcsname#1#2:##1\endcsname}%       ##1 {##2} (braces are mandate)
477       \frozen\protected\def#5##1{\letcsname#1#2:##1\endcsname}%        ##1 ##2
478       \frozen\protected\def#6##1{\letcsname#1#2:##1\endcsname\empty}}% ##1
479% \stopinterface
480
481\permanent\protected\def\installparametersethandler#1#2%
482  {\mutable\letcsname current#2\endcsname\empty
483   \normalexpanded
484     {\mult_interfaces_install_parameter_set_handler
485        {\noexpand#1}% \??aa
486        \expandafter\noexpand\csname current#2\endcsname
487        \expandafter\noexpand\csname set#2parameter\endcsname
488        \expandafter\noexpand\csname setexpanded#2parameter\endcsname
489        \expandafter\noexpand\csname let#2parameter\endcsname
490        \expandafter\noexpand\csname reset#2parameter\endcsname}}
491
492\mutable\let\dousecurrentstyleparameter\relax
493\mutable\let\dousecurrentcolorparameter\relax
494
495\mutable\lettonothing\currentstyleparameter
496\mutable\lettonothing\currentcolorparameter
497
498% maybe we should have \names ones too
499
500\protected\def\mult_interfaces_install_style_and_color_handler#1#2#3#4%
501  {\frozen\protected\def#2##1##2% style color
502     {\cdef\currentstyleparameter{#1{##1}}% this name is public (can also set color e.g. in underline)
503      \ifempty\currentstyleparameter\else\dousecurrentstyleparameter\fi
504      \cdef\currentcolorparameter{#1{##2}}% this name is public (so we do this after the style switch)
505      \ifempty\currentcolorparameter\else\dousecurrentcolorparameter\fi}%
506   \frozen\protected\def#3##1% style
507     {\cdef\currentstyleparameter{#1{##1}}% this name is public
508      \ifempty\currentstyleparameter\else\dousecurrentstyleparameter\fi}%
509   \frozen\protected\def#4##1% color
510     {\cdef\currentcolorparameter{#1{##1}}% this name is public
511      \ifempty\currentcolorparameter\else\dousecurrentcolorparameter\fi}}
512
513\permanent\protected\def\installstyleandcolorhandler#1#2%
514  {\normalexpanded
515     {\mult_interfaces_install_style_and_color_handler
516        \expandafter\noexpand\csname #2parameter\endcsname
517        \expandafter\noexpand\csname use#2styleandcolor\endcsname % maybe an alias use#2styleandcolorparameters
518        \expandafter\noexpand\csname use#2styleparameter\endcsname
519        \expandafter\noexpand\csname use#2colorparameter\endcsname}}
520
521\def\mult_check_for_parent#1#2#3#4%
522  {\ifcsname#1#4:\s!parent\endcsname\orelse\ifx#4\empty\else
523     \writestatus\m!system{error: invalid parent #4 for #3, #4 defined too (best check it)}%
524     \cdefcsname#1#4:\s!parent\endcsname{#2}%
525   \fi}
526
527          \def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\lastnamedcs\space\fi}
528\permanent\def\getparentchain       #1#2{\begincsname#1#2:\s!chain\endcsname}
529\permanent\def\getcurrentparentchain#1#2{\begincsname#1#2:\s!chain\endcsname}
530
531% we could have a \setcurrent... macro and then always make them a frozen
532% but it might have a little impact on performance ... something to leave
533% to when we're done with the transition (it's kind of massive)
534
535\protected\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8%
536  {\newtoks#5%
537   \newtoks#6%
538   \frozen\tolerant\protected\def#2[##1]##*[##S##2]##*[##S##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child]
539     {\let#8#4%
540      % watch out: no \edef#4{##1} before the ifarguments because #1 can have macros
541      \ifarguments
542        \lettonothing#4%
543        \expand#5% predefine
544        \lettonothing#7%
545        \letcsname#1#4:\s!chain\endcsname\empty
546        \cdefcsname#1#4:\s!parent\endcsname{#3}%
547      \or
548        \cdef#4{##1}%
549        \expand#5% predefine
550        \lettonothing#7%
551        \cdefcsname#1#4:\s!chain\endcsname{##1}%
552        \cdefcsname#1#4:\s!parent\endcsname{#3}%
553      \or
554        \cdef#4{##1}%
555        \expand#5% predefine
556        \relax
557        \ifhastok={##2}%
558          \lettonothing#7%
559          \cdefcsname#1#4:\s!chain\endcsname{##1}%
560          \cdefcsname#1#4:\s!parent\endcsname{#3}%
561          \mult_interfaces_get_parameters{#1#4:}[##2]%
562        \else
563          \cdef#7{##2}%
564          \ifempty#7%
565            \cdefcsname#1#4:\s!chain\endcsname{##1}%
566            \cdefcsname#1#4:\s!parent\endcsname{#3}%
567          \else
568            \mult_check_for_parent{#1}{#3}#4#7%
569            \cdefcsname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
570            \cdefcsname#1#4:\s!parent\endcsname{#1##2}%
571          \fi
572        \fi
573      \or
574        \cdef#4{##1}%
575        \expand#5% predefine
576        \cdef#7{##2}%
577        \mult_check_for_parent{#1}{#3}#4#7%
578        \cdefcsname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}%
579        \cdefcsname#1#4:\s!parent\endcsname{#1##2}%
580        \mult_interfaces_get_parameters{#1#4:}[##3]%
581      \fi
582      \expand#6%
583      \let#4#8}}
584
585\permanent\protected\def\installdefinehandler#1#2#3%
586  {\mutable\letcsname current#2\endcsname\empty
587   \mutable\letcsname current#2parent\endcsname\empty
588   \normalexpanded
589     {\mult_interfaces_install_define_handler
590        {\noexpand#1}% \??aa
591        \expandafter\noexpand\csname define#2\endcsname
592        {\noexpand#3}% root
593        \expandafter\noexpand\csname current#2\endcsname
594        \expandafter\noexpand\csname everypreset#2\endcsname
595        \expandafter\noexpand\csname everydefine#2\endcsname
596        \expandafter\noexpand\csname current#2parent\endcsname
597        \expandafter\noexpand\csname saved_defined_#2\endcsname}}
598
599\protected\def\mult_interfaces_install_setup_handler#1#2#3#4#5#6#7#8%
600  {\newtoks#4%
601   \newtoks#7%
602   \frozen\protected\def#5{\mult_interfaces_get_parameters{#1#3:}}% no every ! don't change it
603   \frozen\tolerant\protected\def#2[##S##1]##*[##S##2]% maybe helper
604     {\let#6#3%
605      \ifnum\lastarguments=\plustwo
606        \def#8####1% we will have a simple one as well
607          {\cdef#3{####1}%
608           \mult_interfaces_get_parameters{#1#3:}[##2]%
609           \expand#4}%
610        \processcommalist[##1]#8%
611      \else
612        \lettonothing#3%
613        \mult_interfaces_get_parameters{#1:}[##1]%
614        \expand#4%
615      \fi
616      \let#3#6%
617      \expand#7}}
618
619\permanent\protected\def\installsetuphandler#1#2%
620  {\mutable\letcsname current#2\endcsname\empty
621   \normalexpanded
622     {\mult_interfaces_install_setup_handler
623        {\noexpand#1}% \??aa
624        \expandafter\noexpand\csname setup#2\endcsname
625        \expandafter\noexpand\csname current#2\endcsname
626        \expandafter\noexpand\csname everysetup#2\endcsname
627        \expandafter\noexpand\csname setupcurrent#2\endcsname
628        \expandafter\noexpand\csname saved_setup_current#2\endcsname
629        \expandafter\noexpand\csname everysetup#2root\endcsname
630        \expandafter\noexpand\csname nested_setup_current#2\endcsname}}
631
632\aliased\let\doingrootsetupnamed\plusone    % \setuplayout[name][key=value]
633\aliased\let\doingrootsetuproot \plustwo    % \setuplayout      [key=value]
634\aliased\let\doingrootsetnamed  \plusthree  % \setuplayout[name]
635\aliased\let\doingrootsetroot   \plusfour   % \setuplayout
636
637% \protected\def\mult_interfaces_install_switch_setup_handler_a#1#2#3%
638%   {\frozen\protected\def#3{\mult_interfaces_get_parameters{#1#2:}}}
639
640% \protected\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9%
641%   {\newtoks#5%
642%    \newconstant#2%
643%    \newtoks#8%
644%    \newtoks#9%
645%    \frozen\tolerant\protected\def#4[##1]##*[##2]% maybe helper
646%      {\ifarguments
647%         % \setuplayout
648%         \let#6#3%      % previous becomes current
649%         \lettonothing#3%   % current becomes empty
650%         #2\doingrootsetroot
651%         \expand#5%
652%         \expand#8% switchsetups
653%       \or
654%         \ifhastok={##1}%
655%           % \setuplayout[key=value]
656%           \let#7#3%
657%           \let#6#3%
658%           \lettonothing#3%
659%           #2\doingrootsetuproot
660%           \mult_interfaces_get_parameters{#1:}[##1]%
661%           \expand#5%
662%           \expand#8% switchsetups
663%           \let#3#7%
664%         \else
665%           % \setuplayout[whatever]
666%           \let#6#3%   % previous becomes current
667%           \cdef#3{##1}% this will catch reset so one needs to test for it
668%           \ifempty#3%
669%             \let#7#6%
670%             #2\doingrootsetuproot
671%             \expand#5%
672%             \expand#8% switchsetups
673%             \let#3#7%
674%           \else
675%             #2\doingrootsetnamed
676%             \expand#5%     % we can check for previous vs current
677%             \expand#8% switchsetups
678%           \fi
679%         \fi
680%       \or
681%         % \setuplayout[whatever][key=value]
682%         \let#7#3%
683%         \let#6#3%
684%         \cdef#3{##1}%
685%         #2\doingrootsetupnamed
686%         \mult_interfaces_get_parameters{#1#3:}[##2]%
687%         \expand#5%
688%         \ifx#3#6\expand#8\fi % only switchsetups if previous == current
689%         \let#3#7%
690%       \fi
691%       #2\zerocount % mode is always zero at the end
692%       \expand#9}}
693
694% \permanent\protected\def\installswitchsetuphandler#1#2%
695%   {\mutable\letcsname current#2\endcsname\empty
696%    \mutable\letcsname previous#2\endcsname\empty
697%    \normalexpanded
698%      {\mult_interfaces_install_switch_setup_handler_a
699%         {\noexpand#1}% \??aa
700%         \expandafter\noexpand\csname current#2\endcsname
701%         \expandafter\noexpand\csname setupcurrent#2\endcsname
702%       \mult_interfaces_install_switch_setup_handler_b
703%         {\noexpand#1}% \??aa
704%         \expandafter\noexpand\csname #2setupmode\endcsname
705%         \expandafter\noexpand\csname current#2\endcsname
706%         \expandafter\noexpand\csname setup#2\endcsname
707%         \expandafter\noexpand\csname everysetup#2\endcsname
708%         \expandafter\noexpand\csname previous#2\endcsname
709%         \expandafter\noexpand\csname saved_setup_current#2\endcsname
710%         \expandafter\noexpand\csname everyswitch#2\endcsname
711%         \expandafter\noexpand\csname everysetup#2root\endcsname}}
712
713\protected\def\mult_interfaces_install_switch_setup_handler#1#2#3#4#5#6#7#8#9#A%
714  {\newtoks#5%
715   \newconstant#2%
716   \newtoks#8%
717   \newtoks#9%
718   \frozen\tolerant\protected\def#4[##S##1]##*[##S##2]% maybe helper
719     {\ifarguments
720        % \setuplayout
721        \let#6#3%      % previous becomes current
722        \lettonothing#3%   % current becomes empty
723        #2\doingrootsetroot
724        \expand#5%
725        \expand#8% switchsetups
726      \or
727        \ifhastok={##1}%
728          % \setuplayout[key=value]
729          \let#7#3%
730          \let#6#3%
731          \lettonothing#3%
732          #2\doingrootsetuproot
733          \mult_interfaces_get_parameters{#1:}[##1]%
734          \expand#5%
735          \expand#8% switchsetups
736          \let#3#7%
737        \else
738          % \setuplayout[whatever]
739          \let#6#3%   % previous becomes current
740          \cdef#3{##1}% this will catch reset so one needs to test for it
741          \ifempty#3%
742            \let#7#6%
743            #2\doingrootsetuproot
744            \expand#5%
745            \expand#8% switchsetups
746            \let#3#7%
747          \else
748            #2\doingrootsetnamed
749            \expand#5%     % we can check for previous vs current
750            \expand#8% switchsetups
751          \fi
752        \fi
753      \or
754        % \setuplayout[whatever][key=value]
755        \let#7#3%
756        \let#6#3%
757        \cdef#3{##1}%
758        #2\doingrootsetupnamed
759        \mult_interfaces_get_parameters{#1#3:}[##2]%
760        \expand#5%
761        \ifx#3#6\expand#8\fi % only switchsetups if previous == current
762        \let#3#7%
763      \fi
764      #2\zerocount % mode is always zero at the end
765      \expand#9}%
766    \frozen\protected\def#A{\mult_interfaces_get_parameters{#1#3:}}}
767
768\permanent\protected\def\installswitchsetuphandler#1#2%
769  {\mutable\letcsname current#2\endcsname\empty
770   \mutable\letcsname previous#2\endcsname\empty
771   \normalexpanded
772     {\mult_interfaces_install_switch_setup_handler
773        {\noexpand#1}% \??aa
774        \expandafter\noexpand\csname #2setupmode\endcsname
775        \expandafter\noexpand\csname current#2\endcsname
776        \expandafter\noexpand\csname setup#2\endcsname
777        \expandafter\noexpand\csname everysetup#2\endcsname
778        \expandafter\noexpand\csname previous#2\endcsname
779        \expandafter\noexpand\csname saved_setup_current#2\endcsname
780        \expandafter\noexpand\csname everyswitch#2\endcsname
781        \expandafter\noexpand\csname everysetup#2root\endcsname
782        \expandafter\noexpand\csname setupcurrent#2\endcsname}}
783
784
785\protected\def\mult_interfaces_install_auto_setup_handler#1#2#3#4#5#6#7#8%
786  {\newtoks#4%
787   \frozen\protected\def#5{\mult_interfaces_get_parameters{#1#3:}}%
788   \frozen\tolerant\protected\def#2[##S##1]##*[##S##2]##*[##S##3]%
789     {\let#7#3%
790      \ifarguments
791        \lettonothing#3%
792        \expand#4%
793      \or
794        \lettonothing#3%
795        \mult_interfaces_get_parameters{#1:}[##1]%
796        \expand#4%
797      \or
798        \def#8####1%
799          {\cdef#3{####1}%
800           #6% checks parent and sets if needed
801           \mult_interfaces_get_parameters{#1#3:}[##2]%
802           \expand#4}%
803        \processcommalist[##1]#8%
804      \or
805        \def#8####1%
806          {\cdef#3{####1}%
807           \cdefcsname#1#3:\s!parent\endcsname{#1##2}%
808           \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent
809           \expand#4}%
810        \processcommalist[##1]#8%
811      \fi
812      \let#3#7}}
813
814\permanent\protected\def\installautosetuphandler#1#2%
815  {\mutable\letcsname current#2\endcsname\empty
816   \normalexpanded
817     {\mult_interfaces_install_auto_setup_handler
818        {\noexpand#1}% \??aa
819        \expandafter\noexpand\csname setup#2\endcsname
820        \expandafter\noexpand\csname current#2\endcsname
821        \expandafter\noexpand\csname everysetup#2\endcsname
822        \expandafter\noexpand\csname setupcurrent#2\endcsname
823        \expandafter\noexpand\csname check#2parent\endcsname
824        \expandafter\noexpand\csname saved_setup_current#2\endcsname
825        \expandafter\noexpand\csname nested_setup_current#2\endcsname}}
826
827\permanent\protected\def\installbasicparameterhandler#1#2%
828  {\installparameterhandler    {#1}{#2}%
829   \installparameterhashhandler{#1}{#2}%
830   \installparametersethandler {#1}{#2}%
831   \installrootparameterhandler{#1}{#2}}
832
833\permanent\protected\def\installbasicautosetuphandler#1#2% \??self name \??parent (can be \??self)
834  {\installbasicparameterhandler{#1}{#2}%
835   \installautosetuphandler     {#1}{#2}}
836
837\permanent\protected\def\installstylisticautosetuphandler#1#2% \??self name \??parent (can be \??self)
838  {\installbasicparameterhandler{#1}{#2}%
839   \installautosetuphandler     {#1}{#2}%
840   \installstyleandcolorhandler {#1}{#2}}
841
842\permanent\protected\def\installcommandhandler#1#2#3% \??self name \??parent (can be \??self)
843  {\installbasicparameterhandler{#1}{#2}%
844   \installdefinehandler        {#1}{#2}{#3}%
845   \installsetuphandler         {#1}{#2}%
846   \installstyleandcolorhandler {#1}{#2}}
847
848\permanent\protected\def\installswitchcommandhandler#1#2#3% \??self name \??parent (can be \??self)
849  {\installbasicparameterhandler{#1}{#2}%
850   \installdefinehandler        {#1}{#2}{#3}%
851   \installswitchsetuphandler   {#1}{#2}%
852   \installstyleandcolorhandler {#1}{#2}}
853
854\permanent\protected\def\installautocommandhandler#1#2#3% automatically defined cloned setups
855  {\installbasicparameterhandler{#1}{#2}%
856   \installdefinehandler        {#1}{#2}{#3}%
857   \installautosetuphandler     {#1}{#2}%
858   \installstyleandcolorhandler {#1}{#2}}
859
860\permanent\protected\def\installsimplecommandhandler#1#2#3% no define (experiment) - use \check*parent when defining
861  {\installbasicparameterhandler{#1}{#2}%
862   \installsetuphandler         {#1}{#2}%
863   \installstyleandcolorhandler {#1}{#2}}
864
865%D Many mechanisms have some kind of inheritance in place, and these are the
866%D speed||critical ones. Therefore there is no reason to stick to \type {\@@xxkey}
867%D for the sake of performance. For this reason we also provide a direct variant.
868%D This permits a more consistent treatment of namespaces. A \type
869%D {\whateverparameter} call is three times slower and a \type
870%D {\directwhateverparameter} call two times but for some 100K expansions we only
871%D loose some .1 second which is neglectable given the small amount of expansions in
872%D real runs.
873
874%D We don't need colons for such simple cases.
875
876\protected\def\mult_interfaces_install_direct_parameter_handler#1#2#3#4#5%
877  {\frozen\def#3##1{\begincsname#1##1\endcsname}%
878  %\frozen\def#4##1{\detokenize\expandafter\expandafter\expandafter{\csname#1##1\endcsname}}%
879   \frozen\def#4##1{\expandafter\detokened\csname#1##1\endcsname}%
880   \frozen\def#5##1{\begincsname#1##1\endcsname}}
881
882\permanent\protected\def\installdirectparameterhandler#1#2%
883  {\mutable\letcsname current#2\endcsname\empty
884   \normalexpanded
885     {\mult_interfaces_install_direct_parameter_handler
886        {\noexpand#1}%
887        \expandafter\noexpand\csname current#2\endcsname
888        \expandafter\noexpand\csname #2parameter\endcsname
889        \expandafter\noexpand\csname detokenized#2parameter\endcsname
890        \expandafter\noexpand\csname direct#2parameter\endcsname}}
891
892\protected\def\mult_interfaces_install_direct_setup_handler#1#2#3#4%
893  {\newtoks#4%
894   \frozen\tolerant\protected\def#2[##S##1]{\mult_interfaces_get_parameters#1[##1]\expand#4}%
895   \frozen\protected\def#3{\mult_interfaces_get_parameters#1}}
896
897\permanent\protected\def\installdirectsetuphandler#1#2%
898  {\normalexpanded
899     {\mult_interfaces_install_direct_setup_handler
900        {\noexpand#1}% \??aa
901        \expandafter\noexpand\csname setup#2\endcsname
902        \expandafter\noexpand\csname setupcurrent#2\endcsname % no \every (we use 'current' for consistency)
903        \expandafter\noexpand\csname everysetup#2\endcsname}}
904
905% \startinterface english
906    \protected\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5%
907      {\frozen\protected\def#2##1{\defcsname#1##1\endcsname}%
908       \frozen\protected\def#3##1{\edefcsname#1##1\endcsname}%
909       \frozen\protected\def#4##1{\letcsname#1##1\endcsname}%
910       \frozen\protected\def#5##1{\letcsname#1##1\endcsname\empty}}%
911% \stopinterface
912
913\permanent\protected\def\installdirectparametersethandler#1#2%
914  {\normalexpanded
915     {\mult_interfaces_install_direct_parameter_set_handler
916        {\noexpand#1}% \??aa
917        \expandafter\noexpand\csname set#2parameter\endcsname
918        \expandafter\noexpand\csname setexpanded#2parameter\endcsname
919        \expandafter\noexpand\csname let#2parameter\endcsname
920        \expandafter\noexpand\csname reset#2parameter\endcsname}}
921
922\aliased\let\installdirectstyleandcolorhandler\installstyleandcolorhandler
923
924\permanent\protected\def\installdirectcommandhandler#1#2%
925  {\installdirectparameterhandler    {#1}{#2}%
926   \installdirectsetuphandler        {#1}{#2}%
927   \installdirectparametersethandler {#1}{#2}%
928   \installdirectstyleandcolorhandler{#1}{#2}}
929
930\permanent\protected\def\installsetuponlycommandhandler#1#2%
931  {\installdirectparameterhandler   {#1}{#2}%
932   \installdirectsetuphandler       {#1}{#2}%
933   \installdirectparametersethandler{#1}{#2}}
934
935% Experiment:
936
937% \installcorenamespace {one}
938% \installcorenamespace {two}
939%
940% \installcommandhandler \??one {one} \??one
941% \installcommandhandler \??two {two} \??two
942%
943% \defineone[test] \setupone[test][alpha=first]
944% \definetwo[test] \setuptwo[test][beta=second]
945%
946% \protect
947%
948% \def\currentone{test}
949% \def\currenttwo{test}
950%
951% \relateparameterhandlers {two} {test} {one} {test}
952%
953% yes:\oneparameter{alpha}\par
954% nop:\oneparameter{beta}\par
955% yes:\twoparameter{alpha}\par
956% yes:\twoparameter{beta}\par
957
958\permanent\protected\def\relateparameterhandlers#1#2#3#4% {from} {instance} {to} {instance}
959  {\immutable\edefcsname\csname#1namespace\endcsname#2:\s!parent\endcsname{\csname#3namespace\endcsname#4}}
960
961\permanent\protected\def\relateparameterhandlersbyns#1#2#3#4% {from} {instance} {to} {instance}
962  {\cdefcsname#1#2:\s!parent\endcsname{#3#4}}
963
964%D Here is another experiment:
965
966\protected\def\mult_interfaces_install_action_handler#1#2#3%
967  {\frozen\tolerant\protected\defcsname#1\endcsname[##S##1]##*[##S##2]%
968     {\begingroup
969      \ifarguments
970        \lettonothing#2%
971      \or
972       %\ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004%
973      % \ifcondition\mult_aux_no_assignment_indeed##1\ignorearguments
974      %   \cdef#2{##1}%
975      % \else
976      %   \lettonothing#2%
977      %   #3[##1]%
978      % \fi
979        \ifhastok={##1}%
980          \lettonothing#2%
981          #3[##1]%
982        \else
983          \cdef#2{##1}%
984        \fi
985      \or
986        \cdef#2{##1}%
987        #3[##2]%
988      \fi
989      \directsetup{handler:action:#1}%
990      \endgroup}}
991
992\permanent\protected\def\installactionhandler#1%
993  {\mutable\letcsname current#1\endcsname\empty
994   \normalexpanded
995     {\mult_interfaces_install_action_handler
996        {#1}%
997        \expandafter\noexpand\csname current#1\endcsname
998        \expandafter\noexpand\csname setupcurrent#1\endcsname}}
999
1000% First we had, in tune with the regular system variables:
1001%
1002% \starttyping
1003% \protected\def\installnamespace#1{\defcsname ????#1\endcsname{@@@@#1}}
1004% \stoptyping
1005%
1006% The following variant is nicer and in principle faster but that gets unnoticed
1007% unless lots of expansion happens. Also, we can use long tags but the internal
1008% expansion will be relatively small (and unlikely more than 4 characters). For
1009% instance, \??xx used to expand to @@xx but now becomes for instance 123::. This
1010% is one character more but in quite some cases we had : after such a tag in the
1011% old situation. In the new situation we create more namespaces and don't need that
1012% : any more, so we end up with on the average the same amount of tokens and
1013% definitely less when we consider cases like \??xx:\c!align: which now is just
1014% \??somealign and therefore has length 5 now (instead of 4+1+5+1=10).
1015%
1016% Eventualy we will have a verbose \blablanamespace and the difference between core
1017% and regular can go ... after all, \xxxparameter can already clash between the two
1018% prefix groups .. if users use this mechanism a lot they should use verbose names
1019% anyway (the old two character names were mostly an optimization as they also
1020% expanded to these characters).
1021
1022% todo: register namespaces at lua end for logging and reverse resolve
1023% todo: move this to syst-ini so that we can use it real early
1024
1025\newinteger\c_mult_interfaces_n_of_namespaces
1026
1027% \def\v_interfaces_prefix_template
1028%   {\the\c_mult_interfaces_n_of_namespaces>}
1029
1030\def\v_interfaces_prefix_template
1031  {\tohexadecimal\c_mult_interfaces_n_of_namespaces>}
1032
1033\permanent\protected\def\installnamespace#1% for modules and users
1034  {\ifcsname ????#1\endcsname
1035     \writestatus\m!system{duplicate user namespace '#1'}\wait
1036   \else
1037     \global\advanceby\c_mult_interfaces_n_of_namespaces\plusone
1038     \global\immutable\cdefcsname ????#1\endcsname{\v_interfaces_prefix_template}%
1039   \fi}
1040
1041\permanent\protected\def\installcorenamespace#1%
1042  {\ifcsname ??#1\endcsname
1043     \writestatus\m!system{duplicate core namespace '#1'}\wait
1044   \else
1045     \global\advanceby\c_mult_interfaces_n_of_namespaces\plusone
1046     \global\immutable\cdefcsname ??#1\endcsname{\v_interfaces_prefix_template}%
1047     \clf_registernamespace\c_mult_interfaces_n_of_namespaces{#1}%
1048   \fi}
1049
1050\def\mult_interfaces_get_parameters_error_indeed#1#2%
1051  {\clf_showassignerror{#1}{#2}\inputlineno}
1052
1053% We install two core namespaces here, as we want nice error messages. Maybe
1054% we will reserve the first 9.
1055
1056\installcorenamespace{fontinstanceready}
1057\installcorenamespace{fontinstancebasic}
1058\installcorenamespace{fontinstanceclass}
1059
1060%D The next one is handy for local assignments.
1061
1062\installcorenamespace{dummy}
1063
1064\letvalue\??dummy\empty
1065
1066\permanent          \def\dummyparameter           #1{\begincsname\??dummy#1\endcsname}
1067\permanent          \def\directdummyparameter     #1{\begincsname\??dummy#1\endcsname}
1068\permanent\protected\def\setdummyparameter        #1{\defcsname\??dummy#1\endcsname}
1069\permanent\protected\def\setexpandeddummyparameter#1{\edefcsname\??dummy#1\endcsname}
1070\permanent\protected\def\letdummyparameter        #1{\letcsname\??dummy#1\endcsname}
1071\permanent\protected\def\resetdummyparameter      #1{\letcsname\??dummy#1\endcsname\empty}
1072
1073\edef\mult_interfaces_dummy{\??dummy} % nor immutable
1074
1075% \permanent\protected\def\getdummyparameters[#S#1%
1076%   {\if\noexpand#1]%
1077%      \expandafter\gobbleoneargument
1078%    \else
1079%      \let\m_mult_interfaces_namespace\mult_interfaces_dummy
1080%      \expandafter\mult_interfaces_get_parameters_indeed
1081%    \fi#1}
1082
1083% \permanent\protected\def\getdummyparameters[#S#1]%
1084%   {\let\m_mult_interfaces_namespace\mult_interfaces_dummy
1085%    \mult_interfaces_get_parameters_item_okay#1\ignorearguments\ignorearguments}
1086
1087\permanent\protected\def\getdummyparameters[#S#1]%
1088  {\let\m_mult_interfaces_namespace\mult_interfaces_dummy
1089   \mult_interfaces_get_parameters_item#1\ignorearguments\ignorearguments}
1090
1091\mult_interfaces_install_style_and_color_handler
1092  \directdummyparameter
1093  \usedummystyleandcolor
1094  \usedummystyleparameter
1095  \usedummycolorparameter
1096
1097% Maybe a \definecorenamespace[name][directparameter,directsetup][parent] but we
1098% don't gain much. Actually we might just inline all definitions.
1099
1100% \enabletrackers[interfaces.namespaces,context.flush]
1101%
1102% \definenamespace
1103%   [xy]
1104%   [type=module,
1105%    comment=test module,
1106%    version=1,
1107%    name=test,
1108%    style=yes,
1109%    command=yes,
1110%    setup=list,
1111%    set=yes,
1112%    parent=xy]
1113%
1114% \unprotect
1115% \getparameters
1116%   [\????xy]
1117%   [text=]
1118% \protect
1119%
1120% \definetest[one]
1121%
1122% \starttext
1123%
1124%   “\testparameter{text}”
1125%
1126%   \setuptest[text=foo]
1127%
1128%   “\testparameter{text}”
1129%
1130%   \setuptest[one][text=bar]
1131%
1132%   “\testparameter{text}”
1133%
1134% \stoptext
1135%
1136% This is a user (module) command:
1137
1138\permanent\tolerant\protected\def\definenamespace[#1]#*[#2]% namespace settings
1139  {\clf_definenamespace{#1}{#2}}
1140
1141\permanent\protected\def\listnamespaces
1142  {\clf_listnamespaces}
1143
1144%D Helper:
1145%D
1146%D \starttyping
1147%D \showparentchain{@@am}{left}
1148%D \stoptyping
1149
1150\permanent\protected\def\showparentchain#1#2%
1151  {\writestatus\m!system{chain: [ \mult_interfaces_show_parent_chain{#1#2}]}}
1152
1153\def\mult_interfaces_show_parent_chain#1%
1154  {#1 => %
1155   \ifcsname#1:\s!parent\endcsname
1156      \expandafter\mult_interfaces_show_parent_chain\lastnamedcs
1157   \fi}
1158
1159%D Another helper (needs to be applied):
1160
1161\permanent\protected\def\doifelsecommandhandler#1#2% namespace name
1162  {\ifcsname#1#2:\s!parent\endcsname
1163     \expandafter\firstoftwoarguments
1164   \else
1165     \expandafter\secondoftwoarguments
1166   \fi}
1167
1168\aliased\let\doifcommandhandlerelse\doifelsecommandhandler
1169
1170\permanent\protected\def\doifcommandhandler#1#2% namespace name
1171  {\ifcsname#1#2:\s!parent\endcsname
1172     \expandafter\firstofoneargument
1173   \else
1174     \expandafter\gobbleoneargument
1175   \fi}
1176
1177\permanent\protected\def\doifnotcommandhandler#1#2% namespace name
1178  {\ifcsname#1#2:\s!parent\endcsname
1179     \expandafter\gobbleoneargument
1180   \else
1181     \expandafter\firstofoneargument
1182   \fi}
1183
1184\permanent\def\ifcommandhandler#1#2% namespace name
1185  {\ifcsname#1#2:\s!parent\endcsname}
1186
1187% another set of (fast) helpers (grep for usage):
1188
1189\permanent\def\expandnamespaceparameter#1#2#3% \??xx \getp \c!xx \v!yy
1190  {\csname#1\ifcsname#1\expandafter\expandafter\expandafter\mult_aux_expand_namespace_parameter#2#3}
1191
1192\def\mult_aux_expand_namespace_parameter#1#2% \cs \v!yy
1193  {#1\endcsname#1\else#2\fi\endcsname}
1194
1195\permanent\def\expandnamespacemacro#1#2#3% \??xx \some_edefed_cs \c!yy
1196  {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}
1197
1198\permanent\def\expandnamespacevalue#1#2% \??xx {...} \c!yy == optimized \expandcheckedcsname
1199  {\csname#1\ifcsname#1\normalexpanded{\noexpand\syst_helpers_expand_checked_value{#2}}}
1200
1201\def\syst_helpers_expand_checked_value#1#2%
1202  {#1\endcsname#1\else#2\fi\endcsname}
1203
1204%D Conventions:
1205%D
1206%D \starttyping
1207%D \newinteger     \c_class_whatever
1208%D \newconditional \c_class_whatever
1209%D \newconstant    \c_class_whatever
1210%D \newdimension   \d_class_whatever
1211%D \newgluespec    \s_class_whatever
1212%D \newmuskip      \s_class_whatever
1213%D \newbox         \b_class_whatever
1214%D \newtoks        \t_class_whatever
1215%D
1216%D \edef\p_class_whatever{\classparameter\c!whatever}
1217%D \edef\m_class_whatever{whatever}
1218%D \stoptyping
1219
1220% experiment: in principle this is faster but not that noticeable as we don't do that
1221% many assignments and mechanism that do are also slow; the advantage is mostly nicer
1222% in tracing
1223
1224\mutable\let\c_mult_set\relax
1225
1226\protected\def\mult_interfaces_install_definition_set#1#2#3#4#5#6#7%
1227  {\newinteger#3%
1228   \lettonothing#6%
1229   \protected\def#2%
1230     {\expandafter\let\expandafter\c_mult_set\csname #1_t_#6\endcsname
1231      \ifrelax\c_mult_set
1232        \expandafter\newtoks\c_mult_set
1233        \letcsname#1_t_#6\endcsname\c_mult_set
1234      \fi}
1235   \frozen\protected\def#4##1%
1236     {\pushmacro#6%
1237      \advanceby#3\plusone
1238      \cdef#6{##1}%
1239      \unprotect}%
1240   \frozen\protected\def#5%
1241     {\protect
1242      \advanceby#3\minusone
1243      \popmacro#6}%
1244   \frozen\protected\def#7##1%
1245     {\cdef#6{##1}%
1246      #2%
1247      \the\c_mult_set\relax}}
1248
1249\permanent\protected\def\installdefinitionset#1#2%
1250  {\normalexpanded
1251     {\mult_interfaces_install_definition_set
1252        {\noexpand#1}% \??aa
1253        \expandafter\noexpand\csname set_#2_toks\endcsname
1254        \expandafter\noexpand\csname #2_nesting_depth\endcsname
1255        \expandafter\noexpand\csname push#2\endcsname
1256        \expandafter\noexpand\csname pop#2\endcsname
1257        \expandafter\noexpand\csname current#2\endcsname
1258        \expandafter\noexpand\csname use#2\endcsname}}
1259
1260\protected\def\mult_interfaces_install_definition_set_member#1#2#3#4#5#6#7#8#9% no everysetups etc
1261  {\let#5#2%
1262   \frozen\protected\def#2%
1263     {\ifcase#4\relax\expandafter#5\else\expandafter#6\fi}%
1264   \tolerant\protected\def#6[##S##1]##*[##S##2]%
1265     {\ifarguments\or
1266        #3\toksapp\c_mult_set{#7[##1]}%
1267      \or
1268        #3\toksapp\c_mult_set{#8[##1][##2]}%
1269      \fi}}
1270
1271\permanent\protected\def\installdefinitionsetmember#1#2#3#4%
1272  {\normalexpanded
1273     {\mult_interfaces_install_definition_set_member
1274        {\noexpand#3}% \??aa
1275        \expandafter\noexpand\csname setup#4\endcsname
1276        \expandafter\noexpand\csname set_#2_toks\endcsname
1277        \expandafter\noexpand\csname #2_nesting_depth\endcsname
1278        \expandafter\noexpand\csname normal_setup_#4\endcsname
1279        \expandafter\noexpand\csname delayed_setup_#4\endcsname
1280        \expandafter\noexpand\csname setup#4_\s!single\endcsname
1281        \expandafter\noexpand\csname setup#4_\s!double\endcsname}}
1282
1283%D Another experiment:
1284
1285\protected\def\mult_interfaces_install_parent_injector#1#2#3#4%
1286  {\frozen\protected\def#4##1%
1287     {\ifempty#3%
1288        \cdefcsname#1#2:\s!parent\endcsname{#1##1}% was def
1289      \fi}}
1290
1291\permanent\protected\def\installparentinjector#1#2%
1292  {\normalexpanded{\mult_interfaces_install_parent_injector
1293     {\noexpand#1}%
1294     \expandafter\noexpand\csname current#2\endcsname
1295     \expandafter\noexpand\csname current#2parent\endcsname
1296     \expandafter\noexpand\csname inject#2parent\endcsname}}
1297
1298%D Cheaper (assumes grouping at some point):
1299
1300\permanent\protected\def\mult_interfaces_install_local_current_injector#1#2#3#4%
1301  {\protected\def#4##1%
1302     {\advanceby#2\plusone
1303      \cdef#3{##1:\the#2}% \currentXXX
1304      \cdefcsname#1#3:\s!parent\endcsname{#1##1}}}
1305
1306\permanent\protected\def\installlocalcurrenthandler#1#2% \??XXX {XXX}
1307  {\expandafter\newinteger\csname#1:\s!counter\endcsname
1308   \normalexpanded{\mult_interfaces_install_local_current_injector
1309     {\noexpand#1}%
1310     \expandafter\noexpand\csname #1:\s!counter\endcsname
1311     \expandafter\noexpand\csname current#2\endcsname
1312     \expandafter\noexpand\csname setlocal#2current\endcsname}}
1313
1314%  \unprotect
1315%
1316%  \installcorenamespace {test} \installcommandhandler \??test {test} \??test
1317%  \protected\def\TestMeA[#1]%
1318%    {\edef\currenttest{#1}
1319%     \edef\p_before{\testparameter\c!before}%
1320%     \ifempty\p_before \relax \else \relax \fi}
1321%  \protected\def\TestMeB[#1]%
1322%    {\edef\currenttest{#1}
1323%     \doifelsenothing{\testparameter\c!before}\relax\relax}
1324%  \protected\def\TestMeC[#1]%
1325%    {\edef\currenttest{#1}
1326%     \expandafter\expandafter\expandafter\ifempty\testparameter\c!before \relax \else \relax \fi}
1327%  \protected\def\TestMeD[#1]%
1328%    {\edef\currenttest{#1}
1329%     \doubleexpandafter\ifempty\testparameter\c!before \relax \else \relax \fi}
1330%
1331%  \protect
1332%
1333%  \starttext
1334%    \definetest[foo] \definetest[bar][foo] \setuptest[bar][before=indeed]
1335%    \testfeatureonce{100000}{\TestMeA[bar]} A:\elapsedtime \par % 0.502
1336%    \testfeatureonce{100000}{\TestMeB[bar]} B:\elapsedtime \par % 0.530
1337%    \testfeatureonce{100000}{\TestMeC[bar]} C:\elapsedtime \par % 0.487
1338%    \testfeatureonce{100000}{\TestMeD[bar]} D:\elapsedtime \par % 0.493
1339%  \stoptext
1340
1341% There is no real demand for this ... even if this is two to three times as fast we
1342% only gain a few milliseconds:
1343%
1344% \starttyping
1345% \protected\def\foo#1{[foo:#1]}
1346%
1347% \installcommalistprocessor                        {foo} \foo
1348% \installcommalistprocessorcommand \processfoolist \foo
1349%
1350% \infofont
1351%
1352% \commalistprocessor{foo}[a,b,c,{x,y,z},d]\par
1353% \processfoolist[a, b, c, {x,y,z}, d]\par
1354% \processcommalist[{x,y,z}]\foo\blank
1355%
1356% \commalistprocessor{foo}[{x,y,z},a]\par
1357% \commalistprocessor{foo}[{x,y,z}]\par
1358% \processfoolist[{x,y,z},a]\par
1359% \processfoolist[{x,y,z}]\par
1360% \processcommalist[{x,y,z}]\foo\blank
1361%
1362% \protected\def\foo#1{}
1363%
1364% \testfeatureonce{400000}{\processfoolist         [fixed,middle,bar]}     \elapsedtime\quad
1365%%\testfeatureonce{400000}{\commalistprocessor{foo}[fixed,middle,bar]}     \elapsedtime\quad
1366% \testfeatureonce{400000}{\processcommalist       [fixed,middle,bar]\foo} \elapsedtime\quad
1367% \stoptyping
1368%
1369% For instance the luatex manual only has some 3000 calls. But I keep this around as one
1370% never knows when we might need it.
1371
1372\installcorenamespace{commalistprocessor}
1373\installcorenamespace{commalistprocessoraction}
1374
1375% \installcorenamespace{commalistprocessorwrap}
1376% \installcorenamespace{commalistprocessorfirst}
1377% \installcorenamespace{commalistprocessornext}
1378%
1379% \permanent\protected\def\installcommalistprocessor#1#2% 5 macro names overhead
1380%   {\protected\edefcsname\??commalistprocessor#1\endcsname[%
1381%      {\csname\??commalistprocessorwrap#1\endcsname\relax}% \relax preserves {}
1382%    \protected\edefcsname\??commalistprocessorwrap#1\endcsname##1]%
1383%      {\csname\??commalistprocessorfirst#1\endcsname##S##1,]}%
1384%    \protected\edefcsname\??commalistprocessorfirst#1\endcsname\relax
1385%      {\csname\??commalistprocessornext#1\endcsname}%
1386%    \protected\edefcsname\??commalistprocessornext#1\endcsname
1387%      {\noexpand\futureexpandis]%
1388%         \noexpand\gobbleoneargument
1389%         \csname\??commalistprocessoraction#1\endcsname}
1390%    \protected\edefcsname\??commalistprocessoraction#1\endcsname##1,%
1391%      {\noexpand#2{##1}%
1392%       \csname\??commalistprocessornext#1\endcsname}}
1393
1394\permanent\protected\def\installcommalistprocessor#1#2% 2 macro names overhead
1395  {\tolerant\protected\edefcsname\??commalistprocessor#1\endcsname[##S##1]%
1396     {\csname\??commalistprocessoraction#1\endcsname##1\ignorearguments\ignorearguments}%
1397   \tolerant\protected\edefcsname\??commalistprocessoraction#1\endcsname##S##1,%
1398     {\noexpand\ifarguments\noexpand\or
1399        \noexpand#2{##1}%
1400        \noexpand\expandafter\csname\??commalistprocessoraction#1\endcsname
1401      \noexpand\fi}}
1402
1403\permanent\protected\def\installcommalistprocessorcommand#1#2% \processor \action
1404  {\cdef\p_name{\csstring#2}%
1405   \installcommalistprocessor\p_name{#2}%
1406   \expandafter\let\expandafter#1\csname\??commalistprocessor\p_name\endcsname}
1407
1408\permanent\protected\def\commalistprocessor#1{\csname\??commalistprocessor#1\endcsname}
1409
1410%D This is a special one, used in \METAPOST\ graphic support. It is english only because
1411%D we have no multilingual interface in \METAFUN.
1412
1413\startinterface english
1414    \let\mult_interfaces_install_native_auto_setup_handler\mult_interfaces_install_auto_setup_handler
1415    \aliased\let\installbasicnativeautosetuphandler\installbasicsetuphandler
1416\stopinterface
1417
1418\ifdefined\installnativebasicsetuphandler \else
1419
1420              \let\mult_interfaces_adef_yes\mult_interfaces_adef
1421    \protected\def\mult_interfaces_adef_nop#1#2{\defcsname#1#2\endcsname}
1422
1423    \protected\def\mult_interfaces_install_native_auto_setup_handler#1#2#3#4#5#6#7#8%
1424      {\newtoks#4%
1425       \frozen\protected\def#5{\mult_interfaces_get_parameters{#1#3:}}%
1426       \frozen\tolerant\protected\def#2[##S##1]##*[##S##2]##*[##S##3]%
1427         {\let#7#3%
1428          \ifarguments
1429            \lettonothing#3%
1430            \expand#4%
1431          \or
1432            \lettonothing#3%
1433            \let\mult_interfaces_adef\mult_interfaces_adef_nop
1434            \mult_interfaces_get_parameters{#1:}[##1]%
1435            \let\mult_interfaces_adef\mult_interfaces_adef_yes
1436            \expand#4%
1437          \or
1438            \def#8####1%
1439              {\cdef#3{####1}%
1440               #6% checks parent and sets if needed
1441               \let\mult_interfaces_adef\mult_interfaces_adef_nop
1442               \mult_interfaces_get_parameters{#1#3:}[##2]%
1443               \let\mult_interfaces_adef\mult_interfaces_adef_yes
1444               \expand#4}%
1445            \processcommalist[##1]#8%
1446          \or
1447            \def#8####1%
1448              {\cdef#3{####1}%
1449               \cdefcsname#1#3:\s!parent\endcsname{#1##2}%
1450               \let\mult_interfaces_adef\mult_interfaces_adef_nop
1451               \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent
1452               \let\mult_interfaces_adef\mult_interfaces_adef_yes
1453               \expand#4}%
1454            \processcommalist[##1]#8%
1455          \fi
1456          \let#3#7}}
1457
1458    \permanent\protected\def\installnativeautosetuphandler#1#2%
1459      {\mutable\letcsname current#2\endcsname\empty
1460       \normalexpanded
1461         {\mult_interfaces_install_native_auto_setup_handler
1462            {\noexpand#1}% \??aa
1463            \expandafter\noexpand\csname setup#2\endcsname
1464            \expandafter\noexpand\csname current#2\endcsname
1465            \expandafter\noexpand\csname everysetup#2\endcsname
1466            \expandafter\noexpand\csname setupcurrent#2\endcsname
1467            \expandafter\noexpand\csname check#2parent\endcsname
1468            \expandafter\noexpand\csname saved_setup_current#2\endcsname
1469            \expandafter\noexpand\csname nested_setup_current#2\endcsname}}
1470
1471    \permanent\protected\def\installbasicnativeautosetuphandler#1#2%
1472      {\installbasicparameterhandler {#1}{#2}%
1473       \installnativeautosetuphandler{#1}{#2}}
1474
1475\fi
1476
1477\protect \endinput
1478