I would like to define functions which extract the PDF object number from a PDF object reference, such as 12 from 12 0 R.

I defined two versions of such a function, a low level one and a high level one. The low level function accepts a PDF object reference as a literal string, such as the one given above and extracts the object number 12. This one I got working.

The high level one, however, which accepts a reference as a token list variable unfortunately fails. It should first expand the token list variable and pass it to the low level function. Could someone please find the error in the high level function?

Here is the code I wrote:



\tl_new:Nn\oref{12~0~R} %define some object reference

\cs_new:Npn \lolevel:n #1~0~R {#1}
\cs_new:Nn \hilevel:x {\lolevel:n #1}

Num:~\lolevel:n 12~0~R\par  %this works!
%Num:~\hilevel:x \oref      %doesn't :(


1 Answer 1


There are a few misunderstandings in your code on how argument specifications work, one of which actually causes the issue.

The practical issue is that the definition of \hilevel:x does not do any expansion. Simply giving the function an x argument does not 'magically' carry out expansion. You need to define the expansion either using \cs_generate_variant:Nn (automatic) or within the function itself.

The conceptual misunderstandings are on how you tell what kind of argument things are. First, \lowlevel:n is not a n function: this is a w argument as it's delimited. Secondly, I'd probably go for an o or V expansion here, as you almost certainly don't want to do an x-type expansion. (Every o or V function should have an n equivalent, and in the same way every c function needs an N 'parent'.)

One approach would therefore be

\cs_new:Npn \lolevel:w #1~0~R {#1}
\cs_new:Npn \hilevel:n #1 { \lolevel:w #1 }
\cs_generate_variant:Nn \hilevel:n { V }

or alternatively

\cs_new:Npn \lolevel:w #1~0~R {#1}
\cs_new:Npn \hilevel:n #1 { \lolevel:w #1 }
\cs_new:Npn \hilevel:o #1 { \exp_after:wN \lolevel:w #1 }

optimising the o variant for speed by hand.

  • You could also simply define \hilevel:N with the same definition as \hilevel:o: here it makes perfect sense.
    – Joseph Wright
    Apr 1, 2011 at 14:55
  • Why not defining \hilevel:V at once (which would be a logical directive after reading section 1 of source3.pdf), but the necessity for going the detour via \hilevel:n and \cs_generate_variant:Nn. This is anything but intuitive. I am somewhat disappointed. Thank you anyway for the working code.
    – AlexG
    Apr 4, 2011 at 11:16
  • @Alexander. You can of course define variants directly, but for V it is a bit more involved than in other cases. (V expansion should expand either a macro or a register to it's content, which uses some clear ideas from Morten Hoegholm.) In most cases, the performance gain from a direct definition is pretty marginal, so it's safer to use the automated approach. Conceptually, expansion arg. specs. are supposed to relate back to either n or N in most cases. So the expectation is that the existence of \foo:V implies the existence of \foo:n.
    – Joseph Wright
    Apr 4, 2011 at 11:43
  • @Alexander. As I've also said, in the case outlined I'd probably go for \highlevel:N to take a token list variable as the argument. That would be defined in the same way as \highlevel:o in my answer. You use V where n also makes sense, but use N when you always expect a tl to be passed.
    – Joseph Wright
    Apr 4, 2011 at 11:45
  • @Joseph: Thank you once again! I'd prefer the \cs_new:Npn \hilevel:N #1 { \exp_after:wN \lolevel:w #1 } approach, after all, which is more TeX style. I don't like the :V variant which would choke on {12~0~R} as an argument.
    – AlexG
    Apr 4, 2011 at 13:05

You must log in to answer this question.

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