Will Robertson skrev:
> Hi Lars,
>
> On 06/08/2009, at 10:52 PM, Lars Hellström wrote:
>
>> The xdoc2l3 preprocessing is more about doing things to an argument
>> after you've grabbed it, than about changing the conditions under
>> which it is grabbed.
>
> [...]
>
>> and refer to the scratch variables \l_tmpa_tl, \l_tmpb_tl, etc. where
>> the values are needed, we can have #1, #2, etc. be these cleaned-up
>> values throughout the body.
>
> [...]
>
>> Just bear in mind that what seems esoteric today may be standard
>> practice for the programming technique you'll learn tomorrow.
>
> Sorry for the slow reply; your idea finally clicked in my brain a few
> days ago and the idea has kinda stuck.
Well, I've been slow on reading as well, mostly for weather-related
reasons.
> So let's say we want to define \foo that takes an argument but has to
> sanitise it in some way before processing it:
>
> \DeclareDocumentCommand \foo {m} {
> \my_sanitise:Nn \l_sanitised_tl {#1}
> \foo_internal:V \l_sanitised_tl
> }
> \cs_new:Nn \my_sanitise:Nn {
> % do something with #1 and save it in \l_sanitised_tl
The #1 of \foo, yes.
> }
> \cs_new:Nn \foo_internal:n {
> % do whatever \foo is supposed to do with #1
Which may make use of #1 in several places, some of which may be smack
in the middle of a complex call of some other user-level command, whose
implementation we know very little about...
> }
> \cs_generate_variant:Nn \foo_internal:n {V}
I thought O was the appropriate variant for expanding a token list
control sequence?
> From my not in-depth understanding of xdoc2l3, this can be dramatically
> simplified (I imagine) with something like
>
> \DeclareDocumentCommand \foo { ?{\my_sanitise:n} } {
> % do whatever \foo is supposed to do with #1
> }
Yes. The way I coded it, you would have to declare something as a
"processor", and then be free to combine said processor with other
processors in the specification of an argument; the reason for this was
partly that processors would leave their result "up ahead" as a
mandatory argument that the next processor could operate on.
For example, the processing of an (x,y) argument (xparse "c") would
probably be in two steps:
(x,y)
grab and handle delimiters
{x,y}
split at comma
{{x}{y}}
The most general-purpose processor I defined was "x", but unfortunately
the in-source description of that seems to be wrong (copied from "t"
and only partially rewritten). I believe I gave a more user-oriented
description in a posting to LATEX-L, however.
> Just to confirm -- have I got this thing sort of right? :)
>
> With this sort of example, it seems pretty clear that this can save a
> lot of code that's just shuffling arguments around. (In the same way
> that manual optional argument processing consists of lots of
> intermediate functions that simply pass their arguments around.)
Exactly!
I might add, that with some processing at argument-grabbing time, it
also becomes interesting to do some argument checking and error
reporting there: it is easier to understand _where_ a mandatory
coordinate argument was expected if you get an error message where the
token stream is cut off at precisely the position where the coordinate
was expected.
Lars Hellström
PS: Just to be clear, I don't particularly like (x,y) arguments, but in
this posting they made a good example.
|