2

This example compiles forever. I must be misusing keyval_parse

\documentclass{report}
\usepackage{xparse}

% Relevant doc:
% http://www.texdoc.net/texmf-dist/doc/latex/l3kernel/interface3.pdf#part.21

\ExplSyntaxOn

\NewDocumentCommand{\mykeyvalparser}
{
  m % key
  m % val
}
{
  \tl_case:NnTF #1
  {
    foo{Hello, #2!}
    bar{Bye, #2!}
  }{}{No matching key}

}

\NewDocumentCommand{\mykeyparser}
{
  m % key
}
{
  \tl_case:NnTF #1
  {
    qux{QUX}
  }{}{No matching key}

}


\begin{document}

\keyval_parse:NNn
\mykeyparser
\mykeyvalparser
{
  foo=World,
  bar=Universe,
  qux
}%WANTED: Hello, World! Bye, Universe! QUX

\ExplSyntaxOff

\end{document}

Compile log:

Running `LaTeX' on `parser-1' with ``pdflatex  -file-line-error   -interaction=nonstopmode parser-1.tex''
This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./parser-1.tex
LaTeX2e <2019-10-01>
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/report.cls
Document Class: report 2019/08/27 v1.4j Standard LaTeX document class
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/size10.clo))
(/usr/local/texlive/2019/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
(/usr/local/texlive/2019/texmf-dist/tex/latex/l3kernel/expl3.sty
(/usr/local/texlive/2019/texmf-dist/tex/latex/l3kernel/expl3-code.tex
(/usr/local/texlive/2019/texmf-dist/tex/latex/l3kernel/l3deprecation.def))
(/usr/local/texlive/2019/texmf-dist/tex/latex/l3backend/l3backend-pdfmode.def))) (./parser-1.aux)
./parser-1.tex:45: Missing number, treated as zero.
<to be read again> 
                   o
l.45 }
      %WANTED: Hello, World! Bye, Universe! QUX

UPDATE:

From the cited doc:

\keyval_parse:NNn〈function1〉 〈function2〉{〈key–value list〉}

Thus

\keyval_parse:NNn \function:n \function:nn{ key1 = value1 , key2 = value2, key3 = , key4 }

is converted into an input stream

\function:nn { key1 } { value1 }
\function:nn { key2 } { value2 }\function:nn { key3 } { }\function:n  { key4 }
Erwann
  • 2,100
  • 1
    \tl_case:NnTF #1 doesn't make sense. The key is not of type N What are you expecting it to do? – Ulrike Fischer Jan 05 '20 at 22:23
  • You've not got the right 'cases' syntax for \tl_case:Nn(TF), but you likely want \str_case:nn(TF) anyway. Also (parenthetically), really you should not be document-level commands here. – Joseph Wright Jan 05 '20 at 22:26

1 Answers1

5

As @UlrikeFischer already pointed out in the comments, your usage of \tl_case:NnTF is wrong. Instead you should use \str_case:nnTF here. Also you shouldn't use \NewDocumentCommand for a code level function, which is to be used with \keyval_parse:NNn, so I switched them to code level of the none-existent module my (you should probably change that name). Oh, and also you have to explicitly add spaces with ~ in \ExplSyntaxOn as other spaces are ignored (and ~ is not an unbreakable space as normally but just an ordinary space here).

\documentclass{report}
\usepackage{xparse}

\ExplSyntaxOn
\cs_new:Npn \my_keyval_parser:nn #1 #2
  {
    \str_case:nnTF { #1 }
      {
        { foo } {Hello, ~ #2!}
        { bar } {Bye, ~ #2!}
      }
      {}
      { No ~ matching ~ key}
  }

\cs_new:Npn \my_key_parser:n #1
  {
    \str_case:nnTF { #1 }
      {
        { qux } {QUX}
      }
      {}
      { No ~ matching ~ key}
  }


\begin{document}

\keyval_parse:NNn
\my_key_parser:n
\my_keyval_parser:nn
{
  foo=World,
  bar=Universe,
  qux
}%WANTED: Hello, World! Bye, Universe! QUX

\ExplSyntaxOff

\end{document}

Just as an aside, the correct syntax of \tl_case:NnTF would compare token list variables to token list variables (N-type arguments) and would look like the following in your case (there you'll also see why you want to use \str_case:nn instead):

\tl_new:N \l_my_tmpa_tl
\tl_const:Nn \c__my_foo_tl { foo }
\tl_const:Nn \c__my_bar_tl { bar }
\tl_const:Nn \c__my_qux_tl { qux }
\cs_new_protected:Npn \my_keyval_parser:nn #1 #2
  {
    \tl_set:Nn \l_my_tmpa_tl { #1 }
    \tl_case:NnTF \l_my_tmpa_tl
      {
        \c__my_foo_tl {Hello, ~ #2!}
        \c__my_bar_tl {Bye, ~ #2!}
      }
      {}
      { No ~ matching ~ key}
  }
\cs_new_protected:Npn \my_key_parser:n #1
  {
    \tl_set:Nn \l_my_tmpa_tl { #1 }
    \tl_case:NnTF \l_my_tmpa_tl
      {
        \c__my_qux_tl {QUX}
      }
      {}
      { No ~ matching ~ key}
  }
Skillmon
  • 60,462