%D \module %D [ file=mult-aux, %D version=2010.08.2, %D title=\CONTEXT\ Multilingual Macros, %D subtitle=Helpers, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. %D A generalization of \MKIV-like inheritance. Just something to play with %D (interface might change). The code here evolved in an email exchange between me %D and Wolgang Schuster. \writestatus{loading}{ConTeXt Multilingual Macros / Helpers} \registerctxluafile{mult-aux}{} \unprotect \edef\??empty{\Uchar25} \letvalue{\Uchar25}\empty % hex 19 % \edef\s!parent{\Uchar29} % inlining  is ugly, a tiny bit faster, but neglectable on a run %D \starttyping %D \unprotect %D \def\????aa{@@@@aa} %D %D \installparameterhandler \????aa {whatever} %D \installsetuphandler \????aa {whatever} %D \installdefinehandler \????aa {whatever} \????aa % #3 == defaultroot %D \installfontandcolorhandler\????aa {whatever} %D %D % \installcommandhandler \????aa {whatever} \????aa %D \protect %D %D % \whateverparameter \c!test %D % \whateverparameterhash \c!test %D % \namedwhateverparameter \mycurrentwhatever \c!test %D % \usewhateverstyleandcolor \c!style \c!color %D % \everydefinewhatever (sets \currentwhatever) %D % \everypresetwhatever (can be used to reset parameters as we can redefine) %D % \everysetupwhatever (sets \currentwhatever) %D %D \starttext %D \definewhatever[first] \definewhatever[second][first] %D test: \def\currentwhatever{first} \whateverparameter{method} \par %D \setupwhatever [method=unset] test: \def\currentwhatever{first} \whateverparameter{method} \par %D \setupwhatever[first] [method=first] test: \def\currentwhatever{first} \whateverparameter{method} \par %D test: \def\currentwhatever{second} \whateverparameter{method} \par %D \setupwhatever[second][method=second] test: \def\currentwhatever{second} \whateverparameter{method} \par %D \stoptext %D \stoptyping % problem: every* could clash % % There can be less {} in the following definitions if we assume \??aa and \c!somecs % % todo: \def\detokenized...parameter#1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2\endcsname}} % always root % % it might be more efficient to do this at the lua and % % watch the push/pop and predefinition of current .. this is needed for nested % definitions and overloaded defines using the predefined one % todo: add (relaxed) postsetup and postdefine hooks, just after the everys %D Start of experimental code: especially tables can have many assignments and %D although most time is spent in the typesetting anyway, we can squeeze out a %D little bit. Of course having 500 rows of 50 columns each with some setting does %D not happen that often. One should keep in mind that in the average document %D having some 500 assignments is no exception but there we're talking of %D neglectable runtime for them. Of course in the definitions below there is no real %D gain, only in the generated \setup* commands. Another situation with many %D assignments is \XML\ where we can pass attributes and normally don't do testing %D of them making sense. % % \testfeatureonce{100000}{\getparameters[bla][a=111,b=222,c=333]}% 1.669s % \testfeatureonce{100000}{\mult_interfaces_get_parameters{bla} [a=111,b=222,c=333]}% 1.529s % \testfeatureonce{100000}{\def\m_mult_interfaces_namespace{bla}\mult_interfaces_get_parameters_indeed[a=111,b=222,c=333]}% 1.466s \let\m_mult_interfaces_namespace\empty \def\mult_interfaces_get_parameters#1[#2% {\if\noexpand#2]% \expandafter\gobbleoneargument \else \def\m_mult_interfaces_namespace{#1}% \expandafter\mult_interfaces_get_parameters_indeed \fi#2} \def\mult_interfaces_get_parameters_indeed#1]% namespace already set {\mult_interfaces_get_parameters_item#1,],^^^^0004} \def\mult_interfaces_get_parameters_item#1,#2% #2 takes space before , {\if,#1,% dirty trick for testing #1=empty \expandafter\mult_interfaces_get_parameters_item \else\if]#1% \doubleexpandafter\gobbleoneargument \else \mult_interfaces_get_parameters_assign#1==\empty^^^^0004% % \doubleexpandafter\mult_interfaces_get_parameters_item % saves skipping when at end \fi\fi#2} \def\mult_interfaces_get_parameters_error#1#2% #3% {\mult_interfaces_get_parameters_error_indeed{#1}{#2}% \gobbleoneargument} \def\mult_interfaces_get_parameters_error_indeed#1#2% {\showassignerror{#2}{\the\inputlineno\space(#1)}} \def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004% {\ifx\empty#1\empty \expandafter\mult_interfaces_get_parameters_error \else\ifx#3\empty \doubleexpandafter\mult_interfaces_get_parameters_error \else \doubleexpandafter\mult_interfaces_def \fi\fi \m_mult_interfaces_namespace{#1}{#2}% \doubleexpandafter\mult_interfaces_get_parameters_item} \startinterface english % some 10% faster \let\mult_interfaces_get_parameters_error\undefined \def\mult_interfaces_get_parameters_error_one#1\csname#2#3\endcsname#4% {\mult_interfaces_get_parameters_error_indeed{#2}{#3}\iftrue} \def\mult_interfaces_get_parameters_error_two#1\csname#2#3\endcsname#4% {\mult_interfaces_get_parameters_error_indeed{#2}{#3}} \def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004% {\ifx\empty#1\empty \mult_interfaces_get_parameters_error_one \else\ifx#3\empty \mult_interfaces_get_parameters_error_two \else \expandafter\def\csname\m_mult_interfaces_namespace#1\endcsname{#2}% \fi\fi \doubleexpandafter\mult_interfaces_get_parameters_item} % interesting but not faster % % \def\mult_interfaces_get_parameters_error_one#1\m_mult_interfaces_namespace#2\fi\fi% % {\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#2}\m_mult_interfaces_namespace\s!dummy\fi} % % \def\mult_interfaces_get_parameters_error_two#1\m_mult_interfaces_namespace#2\fi\fi% % {\mult_interfaces_get_parameters_error_indeed\m_mult_interfaces_namespace{#2}\m_mult_interfaces_namespace\s!dummy\fi\fi} % % \def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004% % {\expandafter\def\csname % \ifx\empty#1\empty % \mult_interfaces_get_parameters_error_one % \else\ifx#3\empty % \mult_interfaces_get_parameters_error_two % \else % \m_mult_interfaces_namespace#1% % \fi\fi % \endcsname{#2} % \doubleexpandafter\mult_interfaces_get_parameters_item} \stopinterface \newif\ifassignment \def\mult_check_for_assignment_indeed#1=#2#3^^^^0004% {\if#2^^^^0003\assignmentfalse\else\assignmenttrue\fi} \def\mult_check_for_assignment_indeed_begin_#1=#2#3^^^^0004% {\if#2^^^^0003} \def\mult_check_for_assignment#1% {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=^^^^0003^^^^0003^^^^0004} % End of experimental code. \unexpanded\def\mult_interfaces_let #1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} \unexpanded\def\mult_interfaces_lete#1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname\empty} \unexpanded\def\mult_interfaces_def #1#2{\expandafter\def \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} \unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} \unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} \unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} \startinterface english \unexpanded\def\mult_interfaces_let #1#2{\expandafter \let\csname#1#2\endcsname} \unexpanded\def\mult_interfaces_lete#1#2{\expandafter \let\csname#1#2\endcsname\empty} \unexpanded\def\mult_interfaces_def #1#2{\expandafter \def\csname#1#2\endcsname} \unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1#2\endcsname} \unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1#2\endcsname} \unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1#2\endcsname} \stopinterface % the commented detokenized variant that backtracks ... needs testing usage first % % \let\whatever\relax % % \definetest[oeps][bagger=\whatever] % % \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{bagger}}\meaning\hans\par % \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{reggab}}\meaning\hans\par % % 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}% %D pre-expansion can be a bit faster but handly any effect on a normal run so let's %D go for saving some memory \def\mult_interfaces_detokenize{\expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter} \unexpanded\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8#9% inlining \csname*\endcsname is more efficient (#3 and #6 only) {\ifx#2\relax\let#2\empty\fi % it is hardly faster but produces less expansion tracing \def#3##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}% \def#4##1##2{\ifcsname##1:##2\endcsname##1:##2\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}% %\def#5##1##2{\ifx##1\relax\??empty\else#4{##1}{##2}\fi}% is {} needed around ##1 ? %\def#5##1##2{\ifx##1\relax\??empty\else#4##1{##2}\fi}% is {} needed around ##1 ? \def#5##1##2{\ifx##1\relax^^^^0019\else#4##1{##2}\fi}% is {} needed around ##1 ? \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}% \def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack \def#8##1{\begincsname#1#2:##1\endcsname} \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}} \unexpanded\def\installparameterhandler#1#2% {\normalexpanded {\mult_interfaces_install_parameter_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname #2parameter\endcsname \expandafter\noexpand\csname do#2parameter\endcsname % or : #2_parameter \expandafter\noexpand\csname do#2parentparameter\endcsname % or : #2_parent_parameter \expandafter\noexpand\csname named#2parameter\endcsname \expandafter\noexpand\csname detokenized#2parameter\endcsname \expandafter\noexpand\csname direct#2parameter\endcsname \expandafter\noexpand\csname letfrom#2parameter\endcsname}} % strict#2parameter is gone \unexpanded\def\mult_interfaces_install_root_parameter_handler#1#2#3% {\def#2##1{\detokenize\expandafter\expandafter\expandafter{\csname#1:##1\endcsname}}% always root \def#3##1{\begincsname#1:##1\endcsname}} \unexpanded\def\installrootparameterhandler#1#2% {\normalexpanded {\mult_interfaces_install_root_parameter_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname detokenizedroot#2parameter\endcsname \expandafter\noexpand\csname root#2parameter\endcsname}} \unexpanded\def\mult_interfaces_install_parameter_hash_handler#1#2#3#4#5#6#7#8#9% {\ifx#2\relax\let#2\empty\fi \def#3##1{#1#4{#1#2}{##1}:}% leading #1 was missing .. is this one used? \def#4##1##2{\ifcsname##1:##2\endcsname##1\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}% %\def#5##1##2{\ifx##1\relax\else#4{##1}{##2}\fi}% \def#5##1##2{\ifx##1\relax\else#4##1{##2}\fi}% \def#6{#1#2:}% \def#7##1{#1##1:}% \def#8{\ifx#2\empty\else\ifcsname#1#2:\s!parent\endcsname\else\expandafter\let\csname#1#2:\s!parent\endcsname#1\fi\fi}% \unexpanded\def#9##1{\expandafter\edef\csname#1##1:\s!parent\endcsname{#1#2}}} \unexpanded\def\installparameterhashhandler#1#2% {\expandafter\let\csname#2namespace\endcsname#1% \normalexpanded {\mult_interfaces_install_parameter_hash_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname #2parameterhash\endcsname \expandafter\noexpand\csname do#2parameterhash\endcsname % or : #2_parameter_hash \expandafter\noexpand\csname do#2parentparameterhash\endcsname % or : #2_parent_parameter_hash \expandafter\noexpand\csname current#2hash\endcsname \expandafter\noexpand\csname named#2hash\endcsname \expandafter\noexpand\csname check#2parent\endcsname \expandafter\noexpand\csname chaintocurrent#2\endcsname}} %D In \MKIV\ we can probably use the english variant for all other languages too. % todo: inline the def/let \unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6% {\ifx#2\relax\let#2\empty\fi \unexpanded\def#3{\mult_interfaces_def {#1#2:}}% ##1 {##2} (braces are mandate) \unexpanded\def#4{\mult_interfaces_edef{#1#2:}}% ##1 {##2} (braces are mandate) \unexpanded\def#5{\mult_interfaces_let {#1#2:}}% ##1 ##2 \unexpanded\def#6{\mult_interfaces_lete{#1#2:}}}% ##1 \startinterface english \unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6% {\ifx#2\relax\let#2\empty\fi \unexpanded\def#3##1{\expandafter \def\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate) \unexpanded\def#4##1{\expandafter\edef\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate) \unexpanded\def#5##1{\expandafter \let\csname#1#2:##1\endcsname}% ##1 ##2 \unexpanded\def#6##1{\expandafter \let\csname#1#2:##1\endcsname\empty}}% ##1 \stopinterface \unexpanded\def\installparametersethandler#1#2% {\normalexpanded {\mult_interfaces_install_parameter_set_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname set#2parameter\endcsname \expandafter\noexpand\csname setexpanded#2parameter\endcsname \expandafter\noexpand\csname let#2parameter\endcsname \expandafter\noexpand\csname reset#2parameter\endcsname}} \let\dousecurrentstyleparameter\relax \let\dousecurrentcolorparameter\relax \let\currentstyleparameter\empty \let\currentcolorparameter\empty \unexpanded\def\mult_interfaces_install_style_and_color_handler#1#2#3#4% {\unexpanded\def#2##1##2% style color {\edef\currentstyleparameter{#1{##1}}% this name is public (can also set color e.g. in underline) \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi \edef\currentcolorparameter{#1{##2}}% this name is public (so we do this after the style switch) \ifx\currentcolorparameter\empty\else\dousecurrentcolorparameter\fi}% \unexpanded\def#3##1% style {\edef\currentstyleparameter{#1{##1}}% this name is public \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi}% \unexpanded\def#4##1% color {\edef\currentcolorparameter{#1{##1}}% this name is public \ifx\currentcolorparameter\empty\else\dousecurrentcolorparameter\fi}} \unexpanded\def\installstyleandcolorhandler#1#2% {\normalexpanded {\mult_interfaces_install_style_and_color_handler \expandafter\noexpand\csname #2parameter\endcsname \expandafter\noexpand\csname use#2styleandcolor\endcsname % maybe an alias use#2styleandcolorparameters \expandafter\noexpand\csname use#2styleparameter\endcsname \expandafter\noexpand\csname use#2colorparameter\endcsname}} \let\definehandlerparent\empty \def\mult_check_for_parent#1#2#3#4% {\ifcsname#1#4:\s!parent\endcsname \else \ifx#4\empty \else \writestatus\m!system{error: invalid parent #4 for #3, #4 defined too (best check it)}% \expandafter\edef\csname#1#4:\s!parent\endcsname{#2}% \fi \fi} %def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\space\fi} %def\getparentchain #1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\fi} %def\getcurrentparentchain#1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\fi} \def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\lastnamedcs\space\fi} \def\getparentchain #1#2{\begincsname#1#2:\s!chain\endcsname} \def\getcurrentparentchain#1#2{\begincsname#1#2:\s!chain\endcsname} % \unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones % {\ifx#4\relax\let#4\empty\fi % see \defineregister % \unexpanded\def#2{\dotripleempty#5}% % \newtoks#6% % \newtoks#7% % \unexpanded\def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child] % {\let#9#4% % \edef#4{##1}% % \ifthirdargument % \the#6% predefine % \edef#8{##2}% % \mult_check_for_parent{#1}{#3}#4#8% % \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}% % \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}% % \mult_interfaces_get_parameters{#1#4:}[##3]% % \else\ifsecondargument % \the#6% predefine % \expandafter\mult_check_for_assignment_indeed\detokenize{##2}=^^^^0003^^^^0003^^^^0004% % \ifassignment % \let#8\empty % \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}% % \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}% % \mult_interfaces_get_parameters{#1#4:}[##2]% % \else % \edef#8{##2}% % \mult_check_for_parent{#1}{#3}#4#8% % \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}% % \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}% % \fi % \else % \the#6% predefine % \let#8\empty % \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}% % \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}% % \fi\fi % \the#7% % \let#4#9}} \unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones {\ifx#4\relax\let#4\empty\fi % see \defineregister \unexpanded\def#2{\dotripleempty#5}% \newtoks#6% \newtoks#7% \unexpanded\def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child] {\let#9#4% \edef#4{##1}% \ifthirdargument \the#6% predefine \edef#8{##2}% \mult_check_for_parent{#1}{#3}#4#8% \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}% \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}% \mult_interfaces_get_parameters{#1#4:}[##3]% \else\ifsecondargument \the#6% predefine \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##2}=^^^^0003^^^^0003^^^^0004% \edef#8{##2}% \mult_check_for_parent{#1}{#3}#4#8% \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}% \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}% \else \let#8\empty \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}% \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}% \mult_interfaces_get_parameters{#1#4:}[##2]% \fi \else \the#6% predefine \let#8\empty \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}% \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}% \fi\fi \the#7% \let#4#9}} \unexpanded\def\installdefinehandler#1#2#3% {\normalexpanded {\mult_interfaces_install_define_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname define#2\endcsname {\noexpand#3}% root \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname define_#2\endcsname % semi-public \expandafter\noexpand\csname everypreset#2\endcsname \expandafter\noexpand\csname everydefine#2\endcsname \expandafter\noexpand\csname current#2parent\endcsname \expandafter\noexpand\csname saved_defined_#2\endcsname}} \unexpanded\def\mult_interfaces_install_setup_handler#1#2#3#4#5#6#7#8#9% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dodoubleempty#4}% \unexpanded\def#6{\mult_interfaces_get_parameters{#1#3:}}% no every ! don't change it \newtoks#5% \newtoks#8% \unexpanded\def#4[##1][##2]% maybe helper {\let#7#3% \ifsecondargument \def#9####1% we will have a simple one as well {\edef#3{####1}% \mult_interfaces_get_parameters{#1#3:}[##2]% \the#5}% \processcommalist[##1]#9% \else \let#3\empty \mult_interfaces_get_parameters{#1:}[##1]% \the#5% \fi \let#3#7% \the#8}} \unexpanded\def\installsetuphandler#1#2% {\normalexpanded {\mult_interfaces_install_setup_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname setupcurrent#2\endcsname \expandafter\noexpand\csname saved_setup_current#2\endcsname \expandafter\noexpand\csname everysetup#2root\endcsname \expandafter\noexpand\csname nested_setup_current#2\endcsname}} \let\doingrootsetupnamed\plusone % \setuplayout[name][key=value] \let\doingrootsetuproot \plustwo % \setuplayout [key=value] \let\doingrootsetnamed \plusthree % \setuplayout[name] \let\doingrootsetroot \plusfour % \setuplayout \unexpanded\def\mult_interfaces_install_switch_setup_handler_a#1#2#3#4#5% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dodoubleempty#4}% \unexpanded\def#5{\mult_interfaces_get_parameters{#1#3:}}} % \unexpanded\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9% % {\newtoks#5% % \newconstant#2% % \newtoks#8% % \newtoks#9% % \ifx#6\relax\let#6\empty\fi % \unexpanded\def#4[##1][##2]% maybe helper % {\ifsecondargument % no commalist here % % \setuplayout[whatever][key=value] % \let#7#3% % \let#6#3% % \edef#3{##1}% % #2\doingrootsetupnamed % \mult_interfaces_get_parameters{#1#3:}[##2]% % \the#5% % \ifx#3#6\the#8\fi % only switchsetups if previous == current % \let#3#7% % \else\iffirstargument % % \mult_check_for_assignment{##1}% % \expandafter\mult_check_for_assignment_indeed\detokenize{##1}=^^^^0003^^^^0003^^^^0004% % \ifassignment % % \setuplayout[key=value] % \let#7#3% % \let#6#3% % \let#3\empty % #2\doingrootsetuproot % \mult_interfaces_get_parameters{#1:}[##1]% % \the#5% % \the#8% switchsetups % \let#3#7% % \else % % \setuplayout[whatever] % \let#6#3% % previous becomes current % \edef#3{##1}% this will catch reset so one needs to test for it % #2\doingrootsetnamed % \the#5% % we can check for previous vs current % \the#8% switchsetups % \fi % \else % % \setuplayout % \let#6#3% % previous becomes current % \let#3\empty % current becomes empty % #2\doingrootsetroot % \the#5% % \the#8% switchsetups % \fi\fi % #2\zerocount % mode is always zero at the end % \the#9}} \unexpanded\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9% {\newtoks#5% \newconstant#2% \newtoks#8% \newtoks#9% \ifx#6\relax\let#6\empty\fi \unexpanded\def#4[##1][##2]% maybe helper {\ifsecondargument % no commalist here % \setuplayout[whatever][key=value] \let#7#3% \let#6#3% \edef#3{##1}% #2\doingrootsetupnamed \mult_interfaces_get_parameters{#1#3:}[##2]% \the#5% \ifx#3#6\the#8\fi % only switchsetups if previous == current \let#3#7% \else\iffirstargument % \mult_check_for_assignment{##1}% \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004% % \setuplayout[whatever] \let#6#3% % previous becomes current \edef#3{##1}% this will catch reset so one needs to test for it #2\doingrootsetnamed \the#5% % we can check for previous vs current \the#8% switchsetups \else % \setuplayout[key=value] \let#7#3% \let#6#3% \let#3\empty #2\doingrootsetuproot \mult_interfaces_get_parameters{#1:}[##1]% \the#5% \the#8% switchsetups \let#3#7% \fi \else % \setuplayout \let#6#3% % previous becomes current \let#3\empty % current becomes empty #2\doingrootsetroot \the#5% \the#8% switchsetups \fi\fi #2\zerocount % mode is always zero at the end \the#9}} \unexpanded\def\installswitchsetuphandler#1#2% {\normalexpanded {\mult_interfaces_install_switch_setup_handler_a {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname setupcurrent#2\endcsname \mult_interfaces_install_switch_setup_handler_b {\noexpand#1}% \??aa \expandafter\noexpand\csname #2setupmode\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname previous#2\endcsname \expandafter\noexpand\csname saved_setup_current#2\endcsname \expandafter\noexpand\csname everyswitch#2\endcsname \expandafter\noexpand\csname everysetup#2root\endcsname}} \unexpanded\def\mult_interfaces_install_auto_setup_handler#1#2#3#4#5#6#7#8#9% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dotripleempty#4}% \unexpanded\def#6{\mult_interfaces_get_parameters{#1#3:}}% \newtoks#5% \def#4[##1][##2][##3]% {\let#8#3% \ifthirdargument \def#9####1% {\edef#3{####1}% \expandafter\def\csname#1#3:\s!parent\endcsname{#1##2}% \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent \the#5}% \processcommalist[##1]#9% \else\ifsecondargument \def#9####1% {\edef#3{####1}% #7% checks parent and sets if needed \mult_interfaces_get_parameters{#1#3:}[##2]% \the#5}% \processcommalist[##1]#9% \else \let#3\empty \mult_interfaces_get_parameters{#1:}[##1]% \the#5% \fi\fi \let#3#8}} \unexpanded\def\installautosetuphandler#1#2% {\normalexpanded {\mult_interfaces_install_auto_setup_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname setupcurrent#2\endcsname \expandafter\noexpand\csname check#2parent\endcsname \expandafter\noexpand\csname saved_setup_current#2\endcsname \expandafter\noexpand\csname nested_setup_current#2\endcsname}} \unexpanded\def\installbasicparameterhandler#1#2% {\installparameterhandler {#1}{#2}% \installparameterhashhandler{#1}{#2}% \installparametersethandler {#1}{#2}% \installrootparameterhandler{#1}{#2}} \unexpanded\def\installbasicautosetuphandler#1#2#3% \??self name \??parent (can be \??self) {\installbasicparameterhandler{#1}{#2}% \installautosetuphandler {#1}{#2}} \unexpanded\def\installstylisticautosetuphandler#1#2#3% \??self name \??parent (can be \??self) {\installbasicparameterhandler{#1}{#2}% \installautosetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} \unexpanded\def\installcommandhandler#1#2#3% \??self name \??parent (can be \??self) {\installbasicparameterhandler{#1}{#2}% \installdefinehandler {#1}{#2}{#3}% \installsetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} \unexpanded\def\installswitchcommandhandler#1#2#3% \??self name \??parent (can be \??self) {\installbasicparameterhandler{#1}{#2}% \installdefinehandler {#1}{#2}{#3}% \installswitchsetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} \unexpanded\def\installautocommandhandler#1#2#3% automatically defined cloned setups {\installbasicparameterhandler{#1}{#2}% \installdefinehandler {#1}{#2}{#3}% \installautosetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} \unexpanded\def\installsimplecommandhandler#1#2#3% no define (experiment) - use \check*parent when defining {\installbasicparameterhandler{#1}{#2}% \installsetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} %D Many mechanisms have some kind of inheritance in place, and these are the %D speed||critical ones. Therefore there is no reason to stick to \type {\@@xxkey} %D for the sake of performance. For this reason we also provide a direct variant. %D This permits a more consistent treatment of namespaces. A \type %D {\whateverparameter} call is three times slower and a \type %D {\directwhateverparameter} call two times but for some 100K expansions we only %D loose some .1 second which is neglectable given the small amount of expansions in %D real runs. %D We don't need colons for such simple cases. \unexpanded\def\mult_interfaces_install_direct_parameter_handler#1#2#3#4#5% %%{\def#3##1{\csname\ifcsname#1##1\endcsname#1##1\else\s!empty\fi\endcsname}% {\def#3##1{\begincsname#1##1\endcsname}% \def#4##1{\detokenize\expandafter\expandafter\expandafter{\csname#1##1\endcsname}}% % \def#4##1{\mult_interfaces_detokenize{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}}% \def#5##1{\begincsname#1##1\endcsname}} \unexpanded\def\installdirectparameterhandler#1#2% {\normalexpanded {\mult_interfaces_install_direct_parameter_handler {\noexpand#1}% \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname #2parameter\endcsname \expandafter\noexpand\csname detokenized#2parameter\endcsname \expandafter\noexpand\csname direct#2parameter\endcsname}} \unexpanded\def\mult_interfaces_install_direct_setup_handler#1#2#3#4#5% {\unexpanded\def#2{\dosingleempty#3}% \newtoks#5% \def#3[##1]{\mult_interfaces_get_parameters#1[##1]\the#5}% \def#4{\mult_interfaces_get_parameters#1}} \unexpanded\def\installdirectsetuphandler#1#2% {\normalexpanded {\mult_interfaces_install_direct_setup_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname setupcurrent#2\endcsname % no \every (we use 'current' for consistency) \expandafter\noexpand\csname everysetup#2\endcsname}} \unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5% {\unexpanded\def#2{\mult_interfaces_def #1}% \unexpanded\def#3{\mult_interfaces_edef#1}% \unexpanded\def#4{\mult_interfaces_let #1}% \unexpanded\def#5{\mult_interfaces_let #1\empty}}% \startinterface english \unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5% {\unexpanded\def#2##1{\expandafter \def\csname#1##1\endcsname}% \unexpanded\def#3##1{\expandafter\edef\csname#1##1\endcsname}% \unexpanded\def#4##1{\expandafter \let\csname#1##1\endcsname}% \unexpanded\def#5##1{\expandafter \let\csname#1##1\endcsname\empty}}% \stopinterface \unexpanded\def\installdirectparametersethandler#1#2% {\normalexpanded {\mult_interfaces_install_direct_parameter_set_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname set#2parameter\endcsname \expandafter\noexpand\csname setexpanded#2parameter\endcsname \expandafter\noexpand\csname let#2parameter\endcsname \expandafter\noexpand\csname reset#2parameter\endcsname}} \let\installdirectstyleandcolorhandler\installstyleandcolorhandler \unexpanded\def\installdirectcommandhandler#1#2% {\installdirectparameterhandler {#1}{#2}% \installdirectsetuphandler {#1}{#2}% \installdirectparametersethandler {#1}{#2}% \installdirectstyleandcolorhandler{#1}{#2}} \unexpanded\def\installsetuponlycommandhandler#1#2% {\installdirectparameterhandler{#1}{#2}% \installdirectsetuphandler {#1}{#2}% }% maybe \installdirectparametersethandler {#1}{#2}% % Experiment: % \installcorenamespace {one} % \installcorenamespace {two} % % \installcommandhandler \??one {one} \??one % \installcommandhandler \??two {two} \??two % % \defineone[test] \setupone[test][alpha=first] % \definetwo[test] \setuptwo[test][beta=second] % % \protect % % \def\currentone{test} % \def\currenttwo{test} % % \relateparameterhandlers {two} {test} {one} {test} % % yes:\oneparameter{alpha}\par % nop:\oneparameter{beta}\par % yes:\twoparameter{alpha}\par % yes:\twoparameter{beta}\par \unexpanded\def\relateparameterhandlers#1#2#3#4% {from} {instance} {to} {instance} {\expandafter\edef\csname\csname#1namespace\endcsname#2:\s!parent\endcsname{\csname#3namespace\endcsname#4}} \unexpanded\def\relateparameterhandlersbyns#1#2#3#4% {from} {instance} {to} {instance} {\expandafter\edef\csname#1#2:\s!parent\endcsname{#3#4}} %D Here is another experiment: \unexpanded\def\installactionhandler#1% {\normalexpanded {\mult_interfaces_install_action_handler {#1}% \expandafter\noexpand\csname current#1\endcsname \expandafter\noexpand\csname setupcurrent#1\endcsname \expandafter\noexpand\csname #1_action\endcsname}} % \unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4% % {\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}% % \unexpanded\def#4[##1][##2]% % {\begingroup % \ifsecondargument % \edef#2{##1}% % #3[##2]% % \else\iffirstargument % \doifelseassignment{##1} % {\let#2\empty % #3[##1]}% % {\edef#2{##1}}% % \else % \let#2\empty % \fi\fi % \directsetup{handler:action:#1}% % \endgroup}} \unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4% {\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}% \unexpanded\def#4[##1][##2]% {\begingroup \ifsecondargument \edef#2{##1}% #3[##2]% \else\iffirstargument \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004% \edef#2{##1}% \else \let#2\empty #3[##1]% \fi \else \let#2\empty \fi\fi \directsetup{handler:action:#1}% \endgroup}} % First we had, in tune with the regular system variables: % % \starttyping % \unexpanded\def\installnamespace#1{\setvalue{????#1}{@@@@#1}} % \stoptyping % % The following variant is nicer and in principle faster but that gets unnoticed % unless lots of expansion happens. Also, we can use long tags but the internal % expansion will be relatively small (and unlikely more than 4 characters). For % instance, \??xx used to expand to @@xx but now becomes for instance 123::. This % is one character more but in quite some cases we had : after such a tag in the % old situation. In the new situation we create more namespaces and don't need that % : any more, so we end up with on the average the same amount of tokens and % definitely less when we consider cases like \??xx:\c!align: which now is just % \??somealign and therefore has length 5 now (instead of 4+1+5+1=10). % % Eventualy we will have a verbose \blablanamespace and the difference between core % and regular can go ... after all, \xxxparameter can already clash between the two % prefix groups .. if users use this mechanism a lot they should use verbose names % anyway (the old two character names were mostly an optimization as they also % expanded to these characters). % todo: register namespaces at lua end for logging and reverse resolve % todo: move this to syst-ini so that we can use it real early \newcount\c_mult_interfaces_n_of_namespaces %def\v_interfaces_prefix_template{\number \c_mult_interfaces_n_of_namespaces>} %def\v_interfaces_prefix_template{\characters\c_mult_interfaces_n_of_namespaces>} %def\v_interfaces_prefix_template % consistently %03i> % {\ifnum\c_mult_interfaces_n_of_namespaces<\plusten00\else\ifnum\c_mult_interfaces_n_of_namespaces<\plushundred0\fi\fi % \number\c_mult_interfaces_n_of_namespaces>} \def\v_interfaces_prefix_template {\number\c_mult_interfaces_n_of_namespaces>} \unexpanded\def\installnamespace#1% for modules and users {\ifcsname ????#1\endcsname \writestatus\m!system{duplicate user namespace '#1'}\wait \else \global\advance\c_mult_interfaces_n_of_namespaces\plusone \expandafter\edef\csname ????#1\endcsname{\v_interfaces_prefix_template}% \fi} \unexpanded\def\installcorenamespace#1% {\ifcsname ??#1\endcsname \writestatus\m!system{duplicate core namespace '#1'}\wait \else \global\advance\c_mult_interfaces_n_of_namespaces\plusone \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template}% \clf_registernamespace\c_mult_interfaces_n_of_namespaces{#1}% \fi} \def\mult_interfaces_get_parameters_error_indeed#1#2% {\clf_showassignerror{#1}{#2}\inputlineno} % no longer \waitonfatalerror % We install two core namespaces here, as we want nice error messages. Maybe % we will reserve the first 9. \installcorenamespace{fontinstanceready} \installcorenamespace{fontinstancebasic} \installcorenamespace{fontinstanceclass} %D The next one is handy for local assignments. \installcorenamespace{dummy} \letvalue\??dummy\empty \def\dummyparameter #1{\begincsname\??dummy#1\endcsname} \def\directdummyparameter #1{\begincsname\??dummy#1\endcsname} \unexpanded\def\setdummyparameter #1{\expandafter\def\csname\??dummy#1\endcsname} \unexpanded\def\setexpandeddummyparameter#1{\expandafter\edef\csname\??dummy#1\endcsname} \unexpanded\def\letdummyparameter #1{\expandafter\let\csname\??dummy#1\endcsname} % \unexpanded\def\getdummyparameters % {\mult_interfaces_get_parameters\??dummy} \unexpanded\def\getdummyparameters[#1% {\if\noexpand#1]% \expandafter\gobbleoneargument \else \let\m_mult_interfaces_namespace\??dummy \expandafter\mult_interfaces_get_parameters_indeed \fi#1} \mult_interfaces_install_style_and_color_handler \directdummyparameter \usedummystyleandcolor \usedummystyleparameter \usedummycolorparameter % Maybe a \definecorenamespace[name][directparameter,directsetup][parent] but we % don't gain much. Actually we might just inline all definitions. % \enabletrackers[interfaces.namespaces,context.flush] % % \definenamespace % [xy] % [type=module, % comment=test module, % version=1, % name=test, % style=yes, % command=yes, % setup=list, % set=yes, % parent=xy] % % \unprotect % \getparameters % [\????xy] % [text=] % \protect % % \definetest[one] % % \starttext % % “\testparameter{text}” % % \setuptest[text=foo] % % “\testparameter{text}” % % \setuptest[one][text=bar] % % “\testparameter{text}” % % \stoptext % % This is a user (module) command: \unexpanded\def\definenamespace {\dodoubleargument\mult_interfaces_define_name_space} \def\mult_interfaces_define_name_space[#1][#2]% namespace settings {\clf_definenamespace{#1}{#2}} \def\listnamespaces {\clf_listnamespaces} %D Helper: %D %D \starttyping %D \showparentchain{@@am}{left} %D \stoptyping \unexpanded\def\showparentchain#1#2% {\writestatus\m!system{chain: [ \mult_interfaces_show_parent_chain{#1#2}]}} % \def\mult_interfaces_show_parent_chain#1% % {#1 => % % \ifcsname#1:\s!parent\endcsname % \expandafter\mult_interfaces_show_parent_chain\csname#1:\s!parent\endcsname % \fi} \def\mult_interfaces_show_parent_chain#1% {#1 => % \ifcsname#1:\s!parent\endcsname %\expandafter\mult_interfaces_show_parent_chain\csname#1:\s!parent\endcsname \expandafter\mult_interfaces_show_parent_chain\lastnamedcs \fi} %D Another helper (needs to be applied): \unexpanded\def\doifelsecommandhandler#1#2% namespace name {\ifcsname#1#2:\s!parent\endcsname \expandafter\firstoftwoarguments \else \expandafter\secondoftwoarguments \fi} \let\doifcommandhandlerelse\doifelsecommandhandler \unexpanded\def\doifcommandhandler#1#2% namespace name {\ifcsname#1#2:\s!parent\endcsname \expandafter\firstofoneargument \else \expandafter\gobbleoneargument \fi} \unexpanded\def\doifnotcommandhandler#1#2% namespace name {\ifcsname#1#2:\s!parent\endcsname \expandafter\gobbleoneargument \else \expandafter\firstofoneargument \fi} \let\doifcommandhandlerelse\doifelsecommandhandler % another set of (fast) helpers (grep for usage): \def\expandnamespaceparameter#1#2#3% \??xx \getp \c!xx \v!yy {\csname#1\ifcsname#1\expandafter\expandafter\expandafter\mult_aux_expand_namespace_parameter#2#3} \def\mult_aux_expand_namespace_parameter#1#2% \cs \v!yy {#1\endcsname#1\else#2\fi\endcsname} \def\expandnamespacemacro#1#2#3% \??xx \some_edefed_cs \c!yy {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname} \def\expandnamespacevalue#1#2% \??xx {...} \c!yy == optimized \expandcheckedcsname {\csname#1\ifcsname#1\normalexpanded{\noexpand\syst_helpers_expand_checked_value{#2}}} \def\syst_helpers_expand_checked_value#1#2% {#1\endcsname#1\else#2\fi\endcsname} %D Conventions: %D %D \starttyping %D \newcount \c_class_whatever %D \newconditional \c_class_whatever %D \newconstant \c_class_whatever %D \newdimen \d_class_whatever %D \newskip \s_class_whatever %D \newmuskip \s_class_whatever %D \newbox \b_class_whatever %D \newtoks \t_class_whatever %D %D \edef\p_class_whatever{\classparameter\c!whatever} %D \edef\m_class_whatever{whatever} %D \stoptyping % experiment: in principle this is faster but not that noticeable as we don't do that % many assignments and mechanism that do are also slow; the advantage is mostly nicer % in tracing \def\s!simple{simple} \def\s!single{single} \def\s!double{double} \def\s!triple{triple} % \unexpanded\def\syst_helpers_double_empty#1#2#3% % {\syst_helpers_argument_reset % \doifelsenextoptional % {\syst_helpers_double_empty_one_yes_mult#2#3}% % {\syst_helpers_double_empty_one_nop_mult#1}} % % \def\syst_helpers_double_empty_one_yes_mult#1#2[#3]% % {\firstargumenttrue % \doifelsenextoptional % {\secondargumenttrue#2[{#3}]}% % {\syst_helpers_double_empty_two_nop_mult#1{#3}}} % % \def\syst_helpers_double_empty_one_nop_mult% #1% % {\firstargumentfalse % \secondargumentfalse % }% #1} % % \def\syst_helpers_double_empty_two_nop_mult % {\secondargumentfalse % \if_next_blank_space_token % \expandafter\syst_helpers_double_empty_one_spaced_mult % \else % \expandafter\syst_helpers_double_empty_one_normal_mult % \fi} % % \def\syst_helpers_double_empty_one_spaced_mult#1#2{#1[{#2}] } % \def\syst_helpers_double_empty_one_normal_mult#1#2{#1[{#2}]} % % \unexpanded\def\mult_interfaces_install_setup_handler#1#2#3#4#5#6#7#8% % {\ifx#3\relax\let#3\empty\fi % \unexpanded\def#5{\mult_interfaces_get_parameters{#1#3:}}% no every ! don't change it % \newtoks#4% % \newtoks#7% % \edef\m_mult_interface_setup{\csstring#2_}% % \unexpanded\edef#2{\syst_helpers_double_empty % \csname\m_mult_interface_setup\s!simple\endcsname % \csname\m_mult_interface_setup\s!single\endcsname % \csname\m_mult_interface_setup\s!double\endcsname}% % \unexpanded\expandafter\def\csname\m_mult_interface_setup\s!double\endcsname[##1][##2]% % {\let#6#3% % \def#8####1% we will have a simple one as well % {\edef#3{####1}% % \mult_interfaces_get_parameters{#1#3:}[##2]% % \the#4}% % \processcommalist[##1]#8% % \let#3#6% % \the#7}% % \unexpanded\expandafter\def\csname\m_mult_interface_setup\s!single\endcsname[##1]% % {\let#6#3% % \let#3\empty % \mult_interfaces_get_parameters{#1:}[##1]% % \the#4% % \let#3#6% % \the#7}% % \unexpanded\expandafter\def\csname\m_mult_interface_setup\s!simple\endcsname% % {\let#6#3% % \let#3\empty % \the#4% % \let#3#6% % \the#7}} % \unexpanded\def\installsetuphandler#1#2% % {\normalexpanded % {\mult_interfaces_install_setup_handler % {\noexpand#1}% \??aa % \expandafter\noexpand\csname setup#2\endcsname % \expandafter\noexpand\csname current#2\endcsname % \expandafter\noexpand\csname everysetup#2\endcsname % \expandafter\noexpand\csname setupcurrent#2\endcsname % \expandafter\noexpand\csname saved_setup_current#2\endcsname % \expandafter\noexpand\csname everysetup#2root\endcsname % \expandafter\noexpand\csname nested_setup_current#2\endcsname}} % % \unexpanded\def\syst_helpers_triple_empty#1#2#3#4% % {\syst_helpers_argument_reset % \doifelsenextoptional % {\syst_helpers_triple_empty_one_yes_mult#2#3#4}% % {\syst_helpers_triple_empty_one_nop_mult#1}} % % \def\syst_helpers_triple_empty_one_yes_mult#1#2#3[#4]% % {\firstargumenttrue % \doifelsenextoptional % {\syst_helpers_triple_empty_two_yes_mult#2#3{#4}}% % {\syst_helpers_triple_empty_two_nop_mult#1{#4}}} % % \def\syst_helpers_triple_empty_two_yes_mult#1#2#3[#4]% % {\secondargumenttrue % \doifelsenextoptional % {\thirdargumenttrue#2[{#3}][{#4}]}% % {\syst_helpers_triple_empty_three_nop_mult#1{#3}{#4}}} % % \def\syst_helpers_triple_empty_one_nop_mult % #1% % {\firstargumentfalse % \secondargumentfalse % \thirdargumentfalse % } % #1 % % \def\syst_helpers_triple_empty_two_nop_mult % {\secondargumentfalse % \thirdargumentfalse % \if_next_blank_space_token % \expandafter\syst_helpers_triple_empty_two_spaced_mult % \else % \expandafter\syst_helpers_triple_empty_two_normal_mult % \fi} % % \def\syst_helpers_triple_empty_three_nop_mult % {\thirdargumentfalse % \if_next_blank_space_token % \expandafter\syst_helpers_triple_empty_three_spaced_mult % \else % \expandafter\syst_helpers_triple_empty_three_normal_mult % \fi} % % \def\syst_helpers_triple_empty_two_spaced_mult #1#2{#1[{#2}] } % \def\syst_helpers_triple_empty_two_normal_mult #1#2{#1[{#2}]} % \def\syst_helpers_triple_empty_three_spaced_mult#1#2#3{#1[{#2}][{#3}] } % \def\syst_helpers_triple_empty_three_normal_mult#1#2#3{#1[{#2}][{#3}]} % % \unexpanded\def\mult_interfaces_install_auto_setup_handler#1#2#3#4#5#6#7#8% % {\ifx#3\relax\let#3\empty\fi % \unexpanded\def#5{\mult_interfaces_get_parameters{#1#3:}}% % \newtoks#4% % \edef\m_mult_interface_setup{\csstring#2_}% % \unexpanded\edef#2{\syst_helpers_triple_empty % \csname\m_mult_interface_setup\s!simple\endcsname % \csname\m_mult_interface_setup\s!single\endcsname % \csname\m_mult_interface_setup\s!double\endcsname % \csname\m_mult_interface_setup\s!triple\endcsname}% % \unexpanded\expandafter\def\csname\m_mult_interface_setup\s!triple\endcsname[##1][##2][##3]% % {\let#7#3% % \def#8####1% % {\edef#3{####1}% % \expandafter\def\csname#1#3:\s!parent\endcsname{#1##2}% % \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent % \the#4}% % \processcommalist[##1]#8% % \let#3#7}% % \unexpanded\expandafter\def\csname\m_mult_interface_setup\s!double\endcsname[##1][##2]% % {\let#7#3% % \def#8####1% % {\edef#3{####1}% % #6% checks parent and sets if needed % \mult_interfaces_get_parameters{#1#3:}[##2]% % \the#4}% % \processcommalist[##1]#8% % \let#3#7}% % \unexpanded\expandafter\def\csname\m_mult_interface_setup\s!single\endcsname[##1]% % {\let#7#3% % \let#3\empty % \mult_interfaces_get_parameters{#1:}[##1]% % \the#4% % \let#3#7}% % \unexpanded\expandafter\def\csname\m_mult_interface_setup\s!simple\endcsname% % {\let#7#3% % \let#3\empty % \the#4% % \let#3#7}} % % \unexpanded\def\installautosetuphandler#1#2% % {\normalexpanded % {\mult_interfaces_install_auto_setup_handler % {\noexpand#1}% \??aa % \expandafter\noexpand\csname setup#2\endcsname % \expandafter\noexpand\csname current#2\endcsname % \expandafter\noexpand\csname everysetup#2\endcsname % \expandafter\noexpand\csname setupcurrent#2\endcsname % \expandafter\noexpand\csname check#2parent\endcsname % \expandafter\noexpand\csname saved_setup_current#2\endcsname % \expandafter\noexpand\csname nested_setup_current#2\endcsname}} % okay, we can also get rid of the #9, but this code looks pretty bad, while the previous is % still okay given that we can also use #6 as setup (so in fact we can save some cs again and % only use one extra) % % \global\advance\commalevel \plusone % \expandafter\def\csname\??nextcommalevel\the\commalevel\endcsname####1,% % {\edef#3{####1}% % \mult_interfaces_get_parameters{#1#3:}[##2]% % \the#5% % \syst_helpers_do_process_comma_item}% % \expandafter\syst_helpers_do_do_process_comma_item\gobbleoneargument\relax##1,]\relax % % \syst_helpers_do_do_process_comma_item##1,]\relax % \global\advance\commalevel \minusone % The next one is experimental (and used in publications): \let\c_mult_set\relax \unexpanded\def\mult_interfaces_install_definition_set#1#2#3#4#5#6#7% {\newcount#3% \let#6\empty \unexpanded\def#2% {\expandafter\let\expandafter\c_mult_set\csname #1_t_#6\endcsname \ifx\c_mult_set\relax \expandafter\newtoks\c_mult_set \expandafter\let\csname #1_t_#6\endcsname\c_mult_set \fi} \unexpanded\def#4##1% {\pushmacro#6% \advance#3\plusone \edef#6{##1}% \unprotect}% \unexpanded\def#5% {\protect \advance#3\minusone \popmacro#6}% \unexpanded\def#7##1% {\edef#6{##1}% #2% \the\c_mult_set\relax}} \unexpanded\def\installdefinitionset#1#2% {\normalexpanded {\mult_interfaces_install_definition_set {\noexpand#1}% \??aa \expandafter\noexpand\csname set_#2_toks\endcsname \expandafter\noexpand\csname #2_nesting_depth\endcsname \expandafter\noexpand\csname push#2\endcsname \expandafter\noexpand\csname pop#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname use#2\endcsname}} \unexpanded\def\mult_interfaces_install_definition_set_member#1#2#3#4#5#6#7#8#9% no everysetups etc {\let#5#2% \unexpanded\def#2% {\ifcase#4\relax\expandafter#5\else\expandafter#6\fi}% \unexpanded\def#6% {\dodoubleempty#7}% \unexpanded\def#7[##1][##2]% {\ifsecondargument %#3\c_mult_set\expandafter{\the\c_mult_set#9[##1][##2]}% #3\toksapp\c_mult_set{#9[##1][##2]}% \else\iffirstargument %#3\c_mult_set\expandafter{\the\c_mult_set#8[##1]}% #3\toksapp\c_mult_set{#8[##1]}% \fi\fi}} \unexpanded\def\installdefinitionsetmember#1#2#3#4% {\normalexpanded {\mult_interfaces_install_definition_set_member {\noexpand#3}% \??aa \expandafter\noexpand\csname setup#4\endcsname \expandafter\noexpand\csname set_#2_toks\endcsname \expandafter\noexpand\csname #2_nesting_depth\endcsname \expandafter\noexpand\csname normal_setup_#4\endcsname \expandafter\noexpand\csname delayed_setup_#4\endcsname \expandafter\noexpand\csname do_delayed_setup_#4\endcsname \expandafter\noexpand\csname setup#4_\s!single\endcsname \expandafter\noexpand\csname setup#4_\s!double\endcsname}} %D Another experiment: \unexpanded\def\mult_interfaces_install_parent_injector#1#2#3#4% {\unexpanded\def#4##1% {\ifx#3\empty \expandafter\def\csname#1#2:\s!parent\endcsname{#1##1}% \fi}} \unexpanded\def\installparentinjector#1#2% {\normalexpanded{\mult_interfaces_install_parent_injector {\noexpand#1}% \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname current#2parent\endcsname \expandafter\noexpand\csname inject#2parent\endcsname}} % Faster but not used that much to make a dent in performance. But, because it's % cleaner anyway and also gives less tracing, we apply it a few times. \unexpanded\def\syst_helpers_install_macro_stack#1#2#3% {\xdef\m_syst_helpers_push_macro{\csstring#1}% \ifcsname#3\m_syst_helpers_push_macro\endcsname\else \expandafter\newcount\csname#3\m_syst_helpers_push_macro\endcsname \expandafter\edef\csname push_macro_\m_syst_helpers_push_macro\endcsname {\noexpand\expandafter\glet \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname \noexpand#1% \global\advance\csname#3\m_syst_helpers_push_macro\endcsname\plusone}% \expandafter\edef\csname pop_macro_\m_syst_helpers_push_macro\endcsname {\global\advance\csname#3\m_syst_helpers_push_macro\endcsname\minusone \noexpand\expandafter#2% \noexpand\expandafter\noexpand#1% \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname}% \fi} \unexpanded\def\installmacrostack #1{\syst_helpers_install_macro_stack#1\let \??localpushedmacro } \unexpanded\def\installglobalmacrostack#1{\syst_helpers_install_macro_stack#1\glet\??globalpushedmacro} % \unprotect % % \installcorenamespace {test} \installcommandhandler \??test {test} \??test % \unexpanded\def\TestMeA[#1]% % {\edef\currenttest{#1} % \edef\p_before{\testparameter\c!before}% % \ifx\p_before\empty \relax \else \relax \fi} % \unexpanded\def\TestMeB[#1]% % {\edef\currenttest{#1} % \doifelsenothing{\testparameter\c!before}\relax\relax} % \unexpanded\def\TestMeC[#1]% % {\edef\currenttest{#1} % \expandafter\expandafter\expandafter\ifx\testparameter\c!before\empty \relax \else \relax \fi} % \unexpanded\def\TestMeD[#1]% % {\edef\currenttest{#1} % \doubleexpandafter\ifx\testparameter\c!before\empty \relax \else \relax \fi} % % \protect % % \starttext % \definetest[foo] \definetest[bar][foo] \setuptest[bar][before=indeed] % \testfeatureonce{100000}{\TestMeA[bar]} A:\elapsedtime \par % 0.502 % \testfeatureonce{100000}{\TestMeB[bar]} B:\elapsedtime \par % 0.530 % \testfeatureonce{100000}{\TestMeC[bar]} C:\elapsedtime \par % 0.487 % \testfeatureonce{100000}{\TestMeD[bar]} D:\elapsedtime \par % 0.493 % \stoptext % There is no real demand for this ... even if this is two to three times as fast we % only gain a few milliseconds: % % \starttyping % \unexpanded\def\foo#1{[foo:#1]} % % \installcommalistprocessor {foo} \foo % \installcommalistprocessorcommand \processfoolist \foo % % \infofont % % \commalistprocessor{foo}[a,b,c,{x,y,z},d]\par % \processfoolist[a, b, c, {x,y,z}, d]\par % \processcommalist[{x,y,z}]\foo\blank % % \commalistprocessor{foo}[{x,y,z},a]\par % \commalistprocessor{foo}[{x,y,z}]\par % \processfoolist[{x,y,z},a]\par % \processfoolist[{x,y,z}]\par % \processcommalist[{x,y,z}]\foo\blank % % \unexpanded\def\foo#1{} % % \testfeatureonce{400000}{\processfoolist [fixed,middle,bar]} \elapsedtime\quad %%\testfeatureonce{400000}{\commalistprocessor{foo}[fixed,middle,bar]} \elapsedtime\quad % \testfeatureonce{400000}{\processcommalist [fixed,middle,bar]\foo} \elapsedtime\quad % \stoptyping % % For instance the luatex manual only has some 3000 calls. But I keep this around as one % never knows when we might need it. \installcorenamespace{commalistprocessor} \installcorenamespace{commalistprocessorwrap} \installcorenamespace{commalistprocessorfirst} \installcorenamespace{commalistprocessornext} \installcorenamespace{commalistprocessoraction} \installcorenamespace{commalistprocessorcheck} \installcorenamespace{commalistprocessorspace} \installcorenamespace{commalistprocessorpickup} \installcorenamespace{commalistprocessorfinish} \unexpanded\def\installcommalistprocessor#1#2% 8 macro names overhead {\let\nexttoken\relax \unexpanded\expandafter\edef\csname\??commalistprocessor#1\endcsname[% {\futurelet\nexttoken\csname\??commalistprocessorcheck#1\endcsname}% \unexpanded\expandafter\edef\csname\??commalistprocessorcheck#1\endcsname {\noexpand\ifx\nexttoken]% \noexpand\expandafter\noexpand\gobblethreearguments \noexpand\else \noexpand\expandafter\csname\??commalistprocessorwrap#1\endcsname \noexpand\fi \relax}% this one preserved the next {} \unexpanded\expandafter\edef\csname\??commalistprocessorwrap#1\endcsname##1]% {\csname\??commalistprocessorfirst#1\endcsname##1,]\relax}% \unexpanded\expandafter\edef\csname\??commalistprocessorfirst#1\endcsname##1% picks up \relax {\csname\??commalistprocessornext#1\endcsname}% \unexpanded\expandafter\edef\csname\??commalistprocessornext#1\endcsname {\noexpand\ifx\nexttoken\noexpand\blankspace \noexpand\expandafter\csname\??commalistprocessorspace#1\endcsname \noexpand\else \noexpand\expandafter\csname\??commalistprocessorfinish#1\endcsname \noexpand\fi}% \unexpanded\expandafter\edef\csname\??commalistprocessorfinish#1\endcsname {\noexpand\ifx\nexttoken]% \noexpand\expandafter\noexpand\gobbleoneargument \noexpand\else \noexpand\expandafter\csname\??commalistprocessoraction#1\endcsname \noexpand\fi}% \unexpanded\expandafter\edef\csname\??commalistprocessoraction#1\endcsname##1,% {\noexpand#2{##1}% \futurelet\nexttoken\csname\??commalistprocessornext#1\endcsname}% \let\next\:% \unexpanded\edef \:{\csname\??commalistprocessorspace#1\endcsname}% \unexpanded\expandafter\edef\: {\futurelet\nexttoken\csname\??commalistprocessornext#1\endcsname}% \let\:\next} \unexpanded\def\installcommalistprocessorcommand#1#2% \processor \action {\edef\p_name{\csstring#2}% \installcommalistprocessor\p_name{#2}% \expandafter\let\expandafter#1\csname\??commalistprocessor\p_name\endcsname} \unexpanded\def\commalistprocessor#1{\csname\??commalistprocessor#1\endcsname} \protect \endinput