1
  1. Is there already an (expandable and extendable) interface in xparse/expl3 for testing whether a set of tokens, probably coming from an expl3-n-type argument or an xparse-m-type argument, matches a specifiable pattern, whereby the pattern, in turn, can be specified by providing a list of argument-specifiers?

    Or do you have to tinker something yourself, e.g. using l3regex instead of just providing a list of argument-specifiers?

    (I ask because I don't want to reinvent a wheel in case it already exists.)

In case there is no such interface I don't ask for such a thing to be written for me.

In case there is no such interface I ask whether creating such an interface

  1. makes sense? (I know, this to a certain extent might be opinion-based, but there might as well be technical/factual reasons for neglecting such an interface which I am not aware of.)
  2. was already discussed and, if so, where I can learn more about what others have already thought about this?

Something like

\AtIfTokensFitPattern{⟨tokens to test⟩}%
                     {⟨list of argument-specifiers⟩}
                     {⟨tokens in case ⟨tokens to test⟩ fit the pattern denoted by the ⟨list of argument-specifiers⟩⟩}%
                     {⟨tokens in case ⟨tokens to test⟩ don't fit the pattern denoted by the ⟨list of argument-specifiers⟩⟩}

in

\NewDocumentCommand\macro{ommm}{%
  Some replacement text where arguments
  \IfNoValueTF{#1}{}{\string##1=#1 and } 
  \string##2=#2 and
  \string##3=#3 and
  \string##4=#4 are used.%
}

...

\NewDocumentCommand\CallMacroWithArgumentOnlyIfPossible{m}{% \AtIfTokensFitPattern{#1}{ommm}{\macro#1}{% \PackageError{MyPackage}% {Cannot call \string\macro}% {The argument must match the argument-pattern of \string\macro!\MessageBreak Otherwise it cannot be passed to \string\macro\space without errors!}% }% }%

...

\CallMacroWithArgumentOnlyIfPossible{[A]{B}{C}{D}} → \macro[A]{B}{C}{D}

\CallMacroWithArgumentOnlyIfPossible{{1}{2}{3}} → \macro{1}{2}{3}

\CallMacroWithArgumentOnlyIfPossible{{a}{b}} → \PackageError{MyPackage}% {Cannot call \string\macro}% {The argument must match the argument-pattern of \string\macro!\MessageBreak Otherwise it cannot be passed to \string\macro\space without errors!}%


Such an interface could probably be useful when it comes to passing macro-arguments to other macros.

E.g., in combination with key=value-processors like pgfkeys or the l3keys-package:

Assume you have a key where a value is required and where two cases are possible:

  • In case the tokens forming the value fit the argument-pattern

    ⟨optional argument in square brackets⟩⟨mandatory argument⟩⟨mandatory argument⟩⟨mandatory argument⟩

    prepend the token \macro; \macro denoting a macro which processes tokens according to the specified argument-pattern. I.e., in the value the optional argument may or may not be present.

  • In case the value does not fit the specified argument-pattern raise a comprehensible error-message. (Probably also raise the error-message in case (some of) the mandatory arguments are not nested in braces.)


The question is more of an academic thing, arising from a scenario about passing parameters to other macros via an l3keys-based key=value interface.

For example,
crefname={singular}{plural}
should cause
\crefname{some counter}{singular}{plural}
to be executed.

More general
crefname=⟨value⟩
should cause
\crefname{some counter}⟨value⟩
to be executed.

(\crefname being defined in the cleveref-package.)

However, this works well only if ⟨value⟩ corresponds in form to two undelimited macro arguments.

I can program the test for this particular scenario.

I am interested if there is already a general interface for testing whether the elements of a set of tokens are assignable to a sequence of arguments according to some parameter-text/according to some list of expl3/xparse-argument-specifiers.

The general test would be something like this:

Approach 1:

One by one, if present, gobble arguments according to the list of argument-specifiers. If a non-optional argument is not present, then the set of tokens does not match the specified argument-pattern. If something remains when arguments according to all argument-specifiers are gobbled, then the set of tokens does not match the specified argument-pattern.

So for each argument-type you'd need a test whether the leading tokens of a token-sequence form such an argument. With optional arguments these tests are already implemented. Then you can implement a loop of testing and gobbling.

For delimited arguments, tests and gobbling-macros may need to be defined on the fly.

Approach 2:

Append to the set of tokens to test another set of tokens that forms a sequence of arguments that matches the list of argument-specifiers. Apply a macro to the result which in one go removes arguments according to the argument-specifiers. If the remainder consists exactly of the tokens appended, then the set of tokens in question matches the argument-pattern.

In any case things might get tricky for arguments where expansion plays a rôle because you need to deal with the fact that a test whether expansion yields both no errors and no infinite loop which is reliable to hundred percent seems not feasible. (The problem reminds me of Alan Turing and the Halting Problem.)

Ulrich Diez
  • 28,770
  • Sorry, I couldn't understand what you want (which maybe means the interface you ask doesn't exist, but) could you make a sample non-working code demonstrating such interface? – Phelype Oleinik Aug 13 '21 at 15:04
  • To be quite honest, I have no idea what you are asking about. Is this related? https://tex.stackexchange.com/questions/305806/is-there-a-reliable-way-to-get-the-number-of-arguments-of-a-command – Henri Menke Aug 13 '21 at 15:25
  • @PhelypeOleinik Done. :-) – Ulrich Diez Aug 13 '21 at 15:42
  • @HenriMenke The relationship is at best very distant. :-) I have added some pseudo code to my question in the hope to make more understandable what the question is about. – Ulrich Diez Aug 13 '21 at 15:44
  • 1
    @UlrichDiez No, nothing like that exists that I know of (not in the kernel, definitely). The closest to that in the kernel I implemented in l3debug to translated nNnn into {#1}#2{#3}{#4}. I have been playing with parsing an xparse argument spec here, but still nothing close to what you want. – Phelype Oleinik Aug 13 '21 at 16:21
  • Does making the argument specification part of the \macro name lead in the right direction? (Incoming argument-pattern matches part-of-self). Such that the last one checked, cs-undefined, is the one with the error message. – Cicada Aug 14 '21 at 13:18

0 Answers0