In TeX and LaTeX everything is about processing tokens, about expanding (expandable) macro tokens, etc.
Instead of properly specifying (in words) an algorithm that would describe the desired behavior of the macros \x
and \y
when processing their argument/the tokens of their argument, you just specified four cases of behavior:
Case 1: \x{SomeExpression}
→ Foo ResultOfSomeExpression
Case 2: \y{SomeExpression}
→ Bar ResultOfSomeExpression
Case 3: \x{\y{SomeExpression}}
→ You called x after y
Case 4: \x{\y{SomeExpression}\y{SomeExpression}}
→ Foo Bar ResultOfSomeExpressionBar ResultOfSomeExpression
Are you sure that in Case 4 you do wish the result
Foo Bar ResultOfSomeExpressionBar ResultOfSomeExpression
and you don't wish the result
Foo ResultOfBar ResultOfSomeExpressionBar ResultOfSomeExpression
?
Probably some parentheses would be nice indicating associativity? — Something like:
Foo ResultOf(Bar ResultOf(SomeExpression)Bar ResultOf(SomeExpression))
?
Be that as it may.
Below I implemented a macro \y
and a macro \x
.
The macro \y
just "grabs" its argument (whereby delimiting braces get removed) and returns that argument with the leading phrase Bar ResultOf
added:
Bar ResultOf<Argument>
.
The macro \x
grabs its argument (whereby delimiting braces get removed) and forks three cases:
Case 1: Argument is of pattern
〈control-sequence-token \y
〉 + 〈single undelimited argument〉
In that case you get the phrase: You called x after y
.
Case 2: Argument is of pattern
〈control-sequence-token \y
〉 + 〈something that is not a single undelimited argument, could as well be emptiness〉
In that case you get the phrase Foo <Argument>
.
Case 3: Argument is of any other pattern, can as well be emptiness.
In that case you get the phrase Foo ResultOf<Argument>
.
Be aware that neither did I use any eTeX-extensions or the like, nor did I use any \if..\else..\fi
-tokens, nor do temporary assignments take place.
The circumstance that temporary assignments do not take place makes the macros usable in expansion-contexts as well.
E.g., if you have (e.g. in terms of \@namedef
) defined a macro-token whose name is \You called x after y
, you could call that macro via \csname\x{\y{something}}\endcsname
.
\documentclass[a4paper]{article}
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange,
%% \UD@CheckWhetherNull, \UD@CheckWhetherSingleUndelimitedArg
%%=============================================================================
\makeatletter
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
%% A concern in his posting is that the argument is hit with \string
%% after some expansions which in edge cases might result in unbalancing
%% surrounding \if..\fi-constructs if the macro is used inside of such
%% \if..\fi-constructs.
%%
%% That challenging concern sickened me. ;-)
%%
%% Therefore I decided to implerment a variant where this cannot happen
%% as expansion is forced by \romannumeral:
%%
%% After the first expansion-step, \string is not applied yet.
%% After the second expansion-step, any possibly disturbing remainders
%% are already removed due to \romannumeral-expansion.
%%
%% No eTeX- or whatsoever extensions. No \if.. .Only \romannumeral,
%% digit 0, space token for terminating \romannumeral-expansion,
%% \string, \expandafter, \UD@firstoftwo, \UD@secondoftwo, {, }.
%%
%% May 20, 2016
%%
%% Ulrich Diez (e-mail: ud.usenetcorrespondence@web.de)
%%
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument itself consists of exactly one undelimited
%% argument:
%%.............................................................................
\newcommand\UD@CheckWhetherSingleDelimitedArg[1]{%
\romannumeral0%
\UD@CheckWhetherNull{#1}{\UD@secondoftwo{}}{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%=============================================================================
%% Internal macros of a mechanism checking whether a macro argument is of
%% pattern \y<single undelimited argument> -- the user-level-macro will be
%% \UDAtCheckWhetherLeadingyAndSingleUndelimited
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a \y-token
%%.............................................................................
%% \UDAtCheckWhetherLeadingy{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s 1st token is a
%% \y-token>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s 1st token is not
%% a \y-token>}%
\newcommand\UDAtCheckWhetherLeadingy[1]{%
\romannumeral0\UD@CheckWhetherNull{#1}%
{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
{\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingyB.#1\y}{}}%
}%
\newcommand\UD@CheckWhetherLeadingyB{}%
\long\def\UD@CheckWhetherLeadingyB#1\y{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
{\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
{\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter}\expandafter\expandafter
\expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument is of pattern
%% \y<single undelimited argument>
%%.............................................................................
\newcommand\UDAtCheckWhetherLeadingyAndSingleUndelimited[1]{%
\romannumeral0%
\UDAtCheckWhetherLeadingy{#1}{%
\expandafter\UD@CheckWhetherSingleDelimitedArg
\expandafter{\UD@firstoftwo{}#1}{%
\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo
}%
}{\UD@secondoftwo{}}%
{%
\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo
}%
}%
\makeatother
%% This delivers the texts that you specified.
\newcommand\x[1]{%
\UDAtCheckWhetherLeadingyAndSingleUndelimited{#1}{%
You called x after y%
}{%
\UDAtCheckWhetherLeadingy{#1}{Foo #1}{Foo ResultOf#1}%
}%
}%
\newcommand\y[1]{Bar ResultOf#1}%
%%\newcommand\x[1]{%
%% \UDAtCheckWhetherLeadingyAndSingleUndelimited{#1}{%
%% operation x with the result of applying operation y to #1 as operand%
%% }{%
%% operation x with operand (#1)%
%% }%
%%}%
%%
%%newcommand\y[1]{operation y with operand (#1)}%
\begin{document}
\x{SomeExpression}
\y{SomeExpression}
\x{\y{SomeExpression}}
\x{\y{SomeExpression}\y{SomeExpression}}
\makeatletter
\@namedef{You called x after y}{Calling x after y is nice!}
\@namedef{Foo ResultOfSomethingWeird}{Calling x on something weird is nice too!}
\@namedef{Bar ResultOfSomethingWeird}{Calling y on something weird is nice as well!}
\@namedef{Foo Bar ResultOfSomethingWeirdBar ResultOfSomethingWeird}{Calling x on the square of result of calling y on something weird is extraordinarily nice!}
\makeatother
\csname\x{\y{something weird}}\endcsname
\csname\x{SomethingWeird}\endcsname
\csname\y{SomethingWeird}\endcsname
\csname\x{\y{SomethingWeird}\y{SomethingWeird}}\endcsname
\end{document}
\x{\y{a}}
's output different from\x{\y{a}\y{a}}
, even though they both seem to fall under the "You called\x
after\y
" category? – Werner Nov 2 '16 at 20:07\y
concatenated with\x
directly in\x{\y{a}}
and not\x{\y{a}\y{a}}
? Perhaps I don't understand your use of "directly" (as opposed to indirectly?). – Werner Nov 2 '16 at 20:17\y{a}
(not even just\y
) is the argument of\x
so you wouldn't nrmally say anything is concatenated. – David Carlisle Nov 2 '16 at 20:21