Lars Hellström wrote: > I was thinking more about single spaces, as in > > \moveto 0 0 \curveto 47 0 100 53 100 100 > > (the idea being to express a bunch of graphic data compactly while still > allowing the code to survive reflowing in a text editor), but this is of > course on the boundary of what can be considered LaTeX2e-ish syntax. Personally, I'm not a fan of that input syntax: I prefer something like the pgf approach. However, I did a quick test and as I hoped you can do this with \DeclareDocumentCommand \moveto { u{~} u{~} } { ... } Not sure how robust this is, but if you really want to do it you can at least have a go. > OK, I think I understand how this part of the system works now: > > 1. Processors occur as \xparse_process_arg:n{<code>} items in the > sequence of grabbers (the thing being constructed in > \l_xparse_signature_toks), _before_ the grabber for the argument to > which they will be applied. > > 2. At _runtime_ these pieces of code are placed into scratch functions > with names on the form \xparse_processor_<N>:n, where N=1,2,3,... > depending on how many processors there are. > \l_xparse_processor_total_int is the number of processors stored so far > (for the current argument). > > 3. When a grabber has successfully grabbed an argument, it hands it over > to \xparse_add_arg:n. This function applies the processors that have > been stored (if any), incrementing \l_xparse_processor_use_int as it > goes. Only after all processors have been applied will it append the > result to \l_xparse_args_toks. You'll see that I've now revised this code to make things both (1) clearer and (2) actually work! It turned out I was overcomplicating things, resulting in non-functioning code. > One noticable difference to what I believe was discussed is in the order > of processors. If ">{A} o" means "grab optional argument, then apply A", > then I think it stands to reason that ">{B} >{A} o" should mean "grab > optional argument, then apply A, finally apply B", but as implemented in > revision 1494 it's B before A. (Reversing the processing order would > allow one to do without \l_xparse_processor_use_int.) Things should now work "as advertised" so that ">{B} >{A} o" applies A first, then B. > Finally, there is the issue that a processor has to put the argument in > a toks register. I understand this is for generality (only sane way to > pass along # tokens), but my experience with this type of API is that > one should make it easy to use commands that happen to already exist. In > this case, it would mean to also support a processor that would store > its result in a macro rather than a toks register, since I'm quite sure > this is what people tend to do unless they definitely need a toks register. > > In the current implementation, such processors could be supported by > defining a relative of >{CODE} that instead of > \xparse_process_arg:n{CODE} puts \xparse_process_tl_arg:n{CODE} in the > signature, where > > \cs_new:Nn \xparse_process_tl_arg:n { > \int_incr:N \l_xparse_processor_total_int > \cs_set:cn { > xparse_processor_ \int_use:N \l_xparse_processor_total_int :n > } { > #1 {##1} > \toks_set:No \l_xparse_arg_toks \l_xparse_arg_tl > } > } > > With a continuation-style implementation of processors, it would not > even be necessary to take the detour over \l_xparse_arg_toks. I can see your point, but I'm also wary of making things too complicated. I'll give this some more thought and see if there is a better way around the entire business to avoid the variable issue. >>> * \l_xparse_processor_int and \l_xparse_processor_use_int are >>> documented as "For keeping a count of post-processors and then using >>> them." Well, I could guess about as much from the names alone. What >>> would be more interesting to see spelt out is /how/ these keeps a track >>> of post-processors; what does actual values of these variables mean? At >>> what stage in the process are they used? >> >> I've tried to improve the documentation on this (whether I have I leave >> to others). I've also altered the name \l_xparse_processor_int to >> \l_xparse_processor_total_int. Trying to explain what has to happen here >> is not easy, at least for me. > > That is a catch of literate programming: you can't do it if you can't > explain how your program works. (Of course, it might be argued that one > shouldn't write programs that one cannot explain, period. :-) ) At least > for me, this puts a restriction on how sleepy I can be when programming, > as my ability to produce text tends to disappear before my ability to > produce code... As I've pointed out, this particular piece of code was broken in any case: no wonder I could not explain it! I hope the fixed version also has better comments (I'm concentrating on this to hopefully improve my style). >> the user functions. I've divided internal functions >> into what seem to me to be logical "blocks", > > They could do with finer divisions. 12 pages is quite a lot. I've done some re-arrangement, which I hope breaks the code up more logically and also makes the flow a little clearer. > In the typeset form, there is an index which should provide the same > functionality via hyperlinks (although for some reason all the links > seem to go to page 1; is that just for me or is it broken in l3doc in > general?) I'd noticed that too: Will is in charge of l3doc! (Seriously, I think l3doc needs a good overhaul but Will did take charge of that part of expl3, so for the moment I'm leaving well alone. He has lots of plans, I think.) Thanks again for the comments: they are proving to be very useful, and I think will result in a better xparse all round. -- Joseph Wright