Nested macro envocation - syntax error?

I get a Argument of \\drs has an extra }. when I try to process the following:

\documentclass{article}

\usepackage{tikz}

\newcommand{\drs}[2][lambda/.initial={}]{%
\{%
{\pgfkeys{/drs/.cd, #1, print}}%
\}%
}

\pgfkeys{/drs/.cd,
print/.code = {\pgfkeysvalueof{/drs/lambda}},
lambda/.code = {%
\pgfkeys{/drs/.cd,
list/.list = {#1},
}%
},
list/.code = {\pgfkeys{/drs/lambda/.append = (#1)}}
}

\begin{document}

\drs[lambda={a,b,{\drs[lambda={x}]{Bar}}}]{Foo}

\end{document}


But the number of braces is correct. I suspect this has to do with the order of macro expansion.

Any help would be greatly appreciated.

EDIT: Found a related error (I think):

\documentclass{article}

\usepackage{tikz}

\makeatletter
\pgfkeys{/drs/.cd,
%
% lambda
%
lambda/.code={%
\pgfkeys{/drs/.cd,
lambda list/.list={#1},
lambda string
}%
},
lambda list/.code={\pgfkeys{/drs/lambda/.append={$\lambda$#1.}}},
lambda string/.code=\def\draw@drs@lambda{\pgfkeysvalueof{/drs/lambda}},
%
% presupposition
%
presupposition/.code={%
\pgfkeys{/drs/.cd,
presupposition list/.list={#1},
presupposition string
}%
},
presupposition list/.code={\pgfkeys{/drs/presupposition/.append={#1}}},
presupposition string/.code={\def\draw@drs@presupposition{\pgfkeysvalueof{/drs/presupposition}}},
}

\newcommand{\drs}[2][]{%
\begingroup%
\def\mymacroempty{}%

% DRS building blocks
\def\draw@drs@presupposition{}%
\def\draw@drs@lambda{}%

\pgfkeys{/drs/.cd,
presupposition/.initial={},
lambda/.initial={},
#1
}%

[ presupposition: \draw@drs@presupposition ]%
\endgroup%
}
\makeatother

\begin{document}

\drs[presupposition={\drs[presupposition={m}]{}}]{%
Foo%
}

\end{document}


This works as expected and prints out

[ presupposition: [ presupposition: m]]


Adding a lambda option to the nested \drs call

  \drs[presupposition={\drs[lambda=x,presupposition={m}]{}}]{%
Foo%
}


produces

  [ presupposition: [ presupposition: ]]


The nested presupposition gets gobbled. This has to do with, again, the time of expansion I guess, but have no idea how to fix it. :-)

-
I've updated my answer to match your updated question. –  Loop Space Jun 25 '11 at 16:52

This is a subtle one!

The immediate problem is with the line:

list/.code = {\pgfkeys{/drs/lambda/.append = (#1)}}


A bit of testing shows that \pgfkeys regards = as something special. So anything with an = has to be protected. You can test this with:

\pgfkeys{/drs/lambda/.append = hello=world}
\pgfkeys{/drs/lambda/.show value}
\pgfkeys{/drs/lambda/.append = {hello=world}}
\pgfkeys{/drs/lambda/.show value}


The first time, only hello shows up in the log. The second time we get all of hello=world. So since the \drs... bit in the list has an = in it, it needs to be protected.

At first sight, you would seem to be doing this already since you pass {\drs[lambda={x}]{Bar}} as one of the terms in the list. But a little more experimenting shows that the /.list iterator strips off all grouping so what actually gets passed is \drs[lambda={x}]{Bar} whence the call is:

\pgfkeys{/drs/lambda/.append = (\drs[lambda={x}]{Bar})


which triggers the error. The immediate solution is to put the braces in the list/.code code:

list/.code = {\pgfkeys{/drs/lambda/.append = {(#1)}}}


Testing the value of /drs/lambda shows that it now gets the right thing.

However, fixing that reveals a minor issue with the routine that you have! Because of the order of expansion, the inner \drs is executed after the outer one and so it sees (a)(b)(\drs[lambda={x}]{Bar}) as the initial value of /drs/lambda, to which it adds an \{(x)\} and prints out the full value again: (a)(b)(\drs[lambda={x}]{Bar})\{(x)\}. Which contains another call to \drs. And so on. And so on.

You could try to reverse the order of expansion by fully expanding the argument to the list, #1, before appending it, but I ran in to troubles with that (which I don't fully understand, but seem to be to do with how LaTeX handles commands with optional arguments). An alternative is to blank /drs/lambda with each call to drs since by the time the inner call is executed, the outer call has done its job and is no longer needed. There are a couple of (equivalent) ways to do this. For example,

\newcommand{\drs}[2][lambda/.initial={}]{%
\{%
{\pgfkeys{/drs/.cd, lambda/.initial={}, #1, print}}%
\}%
}


(which rather defeats the object of the default argument so that could be removed.)

With those two modifications, I get:

{(a)(b)({(x)})}


for output.

Update: (to answer the updated question). The second problem is also about grouping (not expansion). When the .list is called, it sees:

\drs [presupposition={m},lambda={a}]{}


As far as it is concerned, that comma is fair game. The pseudo-grouping defined by the square brackets is ignored as it isn't a real grouping. So it splits this up as \drs[presupposition={m} and lambda={a}]{}. This messes up the following.

Fixing this depends on what else you are trying to achieve with these macros, what other kinds of inputs you wanted to be able to process. The simplest fix of all is simply to make the macro \drs have two mandatory arguments rather than one optional and one mandatory. This would ensure that the arguments to the inner call of \drs are protected and not split apart by the outer call. An alternative would be to use key-value pairs in the argument to \drs thus having a single argument which is a list which is then processed by \pgfkeys.

-
Thanks, I guess I still do not understand how optional arguments are handles exactly. The solution I came up with is to write a wrapper macro with an optional argument and call the real macro from it passing {} as a first argument if the optional argument is empty. –  Nickolay Kolev Jun 26 '11 at 8:40
@Nickolay: The thing to remember about LaTeX's optional argument syntax is that there is no actual grouping involved. So in \test[a]{b} then the b is inside a group but the a is not. Thus the a might get messed with by something else (as in your situation) but the b is (mildly) protected. If you can pinpoint what you don't understand, ask a question about it - that's how I've learned about this sort of stuff. –  Loop Space Jun 26 '11 at 17:51