4

Here's a minimal example of what I'm trying to do, whose intent should be obvious (see the comments).

\documentclass{minimal}

\usepackage{xparse}

\NewDocumentCommand \sayhello { } {
    Hello
}

\ExplSyntaxOn
\NewDocumentCommand \foo { m } {
    \use:c {
        \MakeUppercase{\cs_to_str:N #1}
    }
    again
}
\ExplSyntaxOff

\foo{\sayhello} % Should construct \SAYHELLO macro.

\begin{document}

    \sayhello % Should output "Hello".

    \SAYHELLO % Should output "Hello again".

\end{document}

However, I get the following error.

! Missing \endcsname inserted.
<to be read again> 
                   \protect 
l.18 \foo{\sayhello}

I suppose I'm missing some appropriate expansion in the above code, but I'm not sure how to go about it.

8
  • 2
    This has garnered a vote to close and I'm at a loss to understand why. Yes, it seems a strange thing to do but I can well imagine that the real use-case is sufficiently intricate that if the OP had posted that then there'd be comments asking them to trim it down! I frequently find it useful to test my understanding of things by considering edge cases that I'd never use in a real document (not that I'm saying I'd never use this - I actually have used something quite similar) Commented Sep 11, 2021 at 9:29
  • @AndrewStacey "whose intent should be obvious" = no willingness to precisely describe the problem -> need for clarification -> reason for closing Commented Sep 11, 2021 at 13:03
  • 2
    @UlrichDiez My reading would have been "whose intent should be obvious" = thought they had precisely described the problem, so if I need clarification -> reason for commenting. To vote to close without a comment feels a bit harsh to me. Commented Sep 11, 2021 at 14:13
  • @AndrewStacey You are quite right. I'm not actually trying to create an uppercase version of a macro, but I've tried to make my example "minimal", since my real use case involves \MakeUppercase in a more intricate way.
    – Noldorin
    Commented Sep 11, 2021 at 14:26
  • @UlrichDiez I presume you read the (short) code, however? I'm pretty confident that everything that is not self-explanatory (which \sayhello surely is) is appropriately commented. You're welcome to ask for clarification if not. Anyway, I appreciate that you've given an answer!
    – Noldorin
    Commented Sep 11, 2021 at 14:27

2 Answers 2

5

You'll have to actually define the upper case variant. The way your current code works would just directly try to call the upper case named variant whenever you use \foo while it's not yet defined.

Also, you can't use \MakeUppercase inside of \use:c (or \csname ...\endcsname) because it isn't expandable. Instead you could use \str_uppercase:n provided by expl3. The following uses the f-variant of that to first expand \cs_to_str:N before upper casing happens.

Note that this \foo does only work for parameterless macros.

\documentclass[]{article}

\ExplSyntaxOn
\NewDocumentCommand \foo { m }
  {
    \exp_args:Nc \NewDocumentCommand { \str_uppercase:f { \cs_to_str:N #1 } } {}
      { #1~ again }
  }
\ExplSyntaxOff

\NewDocumentCommand \sayhello {} {Hello}
\foo\sayhello

\begin{document}
\sayhello

\SAYHELLO
\end{document}

enter image description here

2
  • Thanks a lot, this does the job nicely.
    – Noldorin
    Commented Sep 11, 2021 at 17:27
  • Accepting this, since it provides a succinct solution, though I certainly appreciate @UlrichDiez's explanation concerning \MakeUppercase too!
    – Noldorin
    Commented Sep 11, 2021 at 23:17
4

The main problem with \MakeUppercase is that

  • a processing-cascade is triggered which also yields non-expandable tokens that are not suitable as components of names of control sequence tokens.
  • the result is delivered nested in a curly-brace-group.

\MakeUppercase is defined as follows:

\DeclareRobustCommand\MakeUppercase[1]{%
  {% -- opening brace of brace-group
    \def\i{I}%
    \def\j{J}%
    \def\reserved@a##1##2{\let##1##2\reserved@a}%
    \expandafter\reserved@a\@uclclist\reserved@b{\reserved@b\@gobble}%
    \let\UTF@two@octets@noexpand\@empty
    \let\UTF@three@octets@noexpand\@empty
    \let\UTF@four@octets@noexpand\@empty
    \protected@edef\reserved@a{\uppercase{#1}}%
    \reserved@a % -- this holds the text wrapped in \uppercase, some symbol-delivering control-sequences replaced by control-sequences that yield the uppercase variant
  }% -- closing brace of brace-group
}%

\MakeUppercase is intended for typesetting-purposes, not for the purpose of providing/modifying names of control-sequence-tokens.

For programming-purposes/for the purpose of providing/modifying names of control-sequence-tokens expl3 brings along \str_uppercase:n/\str_uppercase:f.

Not for daily usage, just for exhibiting the problem the code below provides a variant of \MakeUppercase where things are not placed into a curly-brace-group.

In any case \str_uppercase:n/\str_uppercase:f is to be preferred in the context of names of control-sequences:
\MakeUppercase's uppercasing routine depends on the font-encoding and might deliver tokens which, when typeset, yield the uppercase-variant of the symbol in question, but cannot be used as components of macro-names.

\documentclass{minimal}
\usepackage[T1]{fontenc}

\makeatletter
\DeclareRobustCommand\MyMakeUppercase[1]{%
  {%
    \def\i{I}%
    \def\j{J}%
    \def\reserved@a##1##2{\let##1##2\reserved@a}%
    \expandafter\reserved@a \@uclclist\reserved@b{\reserved@b\@gobble}%
    \let\UTF@two@octets@noexpand\@empty
    \let\UTF@three@octets@noexpand\@empty
    \let\UTF@four@octets@noexpand\@empty
    \protected@edef\reserved@a{\uppercase{#1}}%
    % \show\reserved@a
  \expandafter}\reserved@a
}%
\makeatother


\usepackage{xparse}

\NewDocumentCommand\sayhello{}{Hello}

\ExplSyntaxOn
\NewDocumentCommand \foo { m } {
    \MyMakeUppercase{\exp_not:n{\exp_args:Nc\NewDocumentCommand}{\cs_to_str:N #1}}{}
    {#1~again}
}
\ExplSyntaxOff

\foo{\sayhello} % Should construct \SAYHELLO macro.

\begin{document}

    \sayhello % Should output "Hello".

    \SAYHELLO % Should output "Hello again".

\end{document}

enter image description here

1
  • Thank you, that makes sense.
    – Noldorin
    Commented Sep 11, 2021 at 17:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .