4

I have LaTeX3 code for a macro that processes its parameters in a complicated way and builds a tree-like structure. To represent this structure it constructs a comma-separated list of strings and comma-separated lists (e.g. a,{b,c}). It does not use the clist interface, but adds brackets and strings to a tokenlist that is processed with \clist_new:NV later.

My problem is: I have no idea how to add a single curly bracket to a tokenlist without unbalancing the code. I tried it with \c_group_begin_token and \c_group_end_token but they did not expand to braces.

How to add clist-grouping braces to a tokenlist?

MWE:

\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn
\DeclareDocumentCommand{\foo}{mmm}{
  \cs_new:Nn \__begin_bracket: {[}  
  \cs_new:Nn \__end_bracket: {]}  
  %\cs_new:Nn \__begin_bracket: {\c_group_begin_token}  
  %\cs_new:Nn \__end_bracket: {\c_group_begin_token} 

  % This processing is more complicated in reality.
  \tl_clear:N \l_tmpa_tl
  \tl_put_right:Nn \l_tmpa_tl {#1 , }
  \tl_put_right:Nx \l_tmpa_tl {\__begin_bracket:}
  \tl_put_right:Nn \l_tmpa_tl {#2 , }
  \tl_put_right:Nn \l_tmpa_tl {#3}
  \tl_put_right:Nx \l_tmpa_tl {\__end_bracket:}

  \tl_log:N \l_tmpa_tl

  \clist_set:NV \l_tmpa_clist \l_tmpa_tl
  \clist_map_inline:Nn \l_tmpa_clist {
    \tl_log:n {##1}
  }
}
\ExplSyntaxOff

\begin{document}
\foo{a}{b}{c}
\end{document}

When altering \__begin_bracket: and \__end_bracket: the output in the logfile should be:

\l_tmpa_tl=a,{b,c}.
a.
b,c.

Note: In a previous version of this question I used brackets around the whole list. This does not work with \clist_set:NV (it assumes I want to escape the comma with the braces).

1 Answer 1

5

You can't have unbalanced token lists; you can use a small trick, though:

\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new:Nn \khb_left_brace:  { { \if_false: } \fi: }
\cs_new:Nn \khb_right_brace: { \if_false: { \fi: } }

\NewDocumentCommand{\foo}{mmm}{

  % This processing is more complicated in reality.
  \tl_clear:N \l_tmpa_tl
  \tl_put_right:Nn \l_tmpa_tl {\exp_not:n {#1 ,} }
  \tl_put_right:Nn \l_tmpa_tl {\khb_left_brace:}
  \tl_put_right:Nn \l_tmpa_tl {\exp_not:n {#2 ,} }
  \tl_put_right:Nn \l_tmpa_tl {\exp_not:n {#3} }
  \tl_put_right:Nn \l_tmpa_tl {\khb_right_brace:}

  \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl }

  \tl_log:N \l_tmpa_tl

  \clist_set:NV \l_tmpa_clist \l_tmpa_tl
  \clist_map_inline:Nn \l_tmpa_clist {
    \tl_log:n {##1}
  }
}
\ExplSyntaxOff

\begin{document}
\foo{a}{b}{c}
\end{document}

The log file has

> \l_tmpa_tl=a,{b,c}.
> a.
> b,c.

as expected

5
  • Thanks. I don't need the \exp_not:n if my arguments are not expandable. Correct?
    – K-HB
    Sep 7, 2018 at 20:54
  • @K-HB Yes, but since you need to do an x-expansion anyway, it doesn't hurt and is safer in case your arguments become something else. Define syntactic sugar such as \cs_new_protected:Nn \khb_tl_partial_put:Nn { \tl_put_right:Nn #1 { \exp_not:n { #2 } } }
    – egreg
    Sep 7, 2018 at 21:00
  • The last line of the log shows it didn't really work (only one list-item). I found my mistake in the MWE. Please see at the new note in the question.
    – K-HB
    Sep 7, 2018 at 22:10
  • @K-HB It does work according to the proposed code. The outer braces should not be added, if you want a two item list. Fixed.
    – egreg
    Sep 7, 2018 at 22:15
  • So the mistake was in my MWE. It didn't fit to my question.
    – K-HB
    Sep 7, 2018 at 22:17

You must log in to answer this question.

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