Prevent xparse from stripping braces?












6














So I'm trying to implement a COOL-style Sum macro which is supposed to support the following syntax:



Sum{ldots}  % -> sum ldots
Sum[i]{ldots} % -> sum_{i} ldots
Sum[i in I]{ldots} % -> sum_{i in I} ldots
Sum[i, 0, N]{ldots} % -> sum_{i=0}^{N} ldots
Sum[{i,j}, 0, N]{ldots} % -> sum_{i,j=0}^{N} ldots
Sum[{i,j,k}]{ldots} % -> sum_{i,j,k} ldots


The important bit is that I would like braces to protect commas in the first argument. The actual implementation is in expl3 with the user interface using xparse. Unfortunately, xparse appears to always strip braces inside arguments if they surround the whole argument such that this protection will not work in all cases, no matter what my internal code does. Looking at the docs, I couldn't find a way to prevent this.



I tried macros signatures of the forms



DeclareDocumentCommand Sum { s >{ SplitArgument{2}{,} } o m }
{ ... }
DeclareDocumentCommand Sum { s o m }
{ ... }


Am I missing something here, is there a (undocumented) way to make xparse not strip such braces short of circumventing xparse and implementing the interface manually (maybe using argument processors?)? If not, would this warrant a bug report/feature request at the latex github?










share|improve this question






















  • Not a solution: You could input Sum[{{i,j,k}}]{ldots}.
    – Skillmon
    Dec 15 '18 at 13:57






  • 3




    Why not simply using ; as delimiter? You would need no braces.
    – egreg
    Dec 15 '18 at 14:03












  • Using ; would likely work for my usecases, I don't think I've ever used a semicolon in sum limits. Still, wrapping the argument in braces was the first and obvious (to me) thing I tried to protect arguments that contain the delimiter, and I was surprised that this didn't work. Maybe I'll go for ';' plus the workaround from the other answers (even though that might be overkill)
    – Wisperwind
    Dec 16 '18 at 13:05
















6














So I'm trying to implement a COOL-style Sum macro which is supposed to support the following syntax:



Sum{ldots}  % -> sum ldots
Sum[i]{ldots} % -> sum_{i} ldots
Sum[i in I]{ldots} % -> sum_{i in I} ldots
Sum[i, 0, N]{ldots} % -> sum_{i=0}^{N} ldots
Sum[{i,j}, 0, N]{ldots} % -> sum_{i,j=0}^{N} ldots
Sum[{i,j,k}]{ldots} % -> sum_{i,j,k} ldots


The important bit is that I would like braces to protect commas in the first argument. The actual implementation is in expl3 with the user interface using xparse. Unfortunately, xparse appears to always strip braces inside arguments if they surround the whole argument such that this protection will not work in all cases, no matter what my internal code does. Looking at the docs, I couldn't find a way to prevent this.



I tried macros signatures of the forms



DeclareDocumentCommand Sum { s >{ SplitArgument{2}{,} } o m }
{ ... }
DeclareDocumentCommand Sum { s o m }
{ ... }


Am I missing something here, is there a (undocumented) way to make xparse not strip such braces short of circumventing xparse and implementing the interface manually (maybe using argument processors?)? If not, would this warrant a bug report/feature request at the latex github?










share|improve this question






















  • Not a solution: You could input Sum[{{i,j,k}}]{ldots}.
    – Skillmon
    Dec 15 '18 at 13:57






  • 3




    Why not simply using ; as delimiter? You would need no braces.
    – egreg
    Dec 15 '18 at 14:03












  • Using ; would likely work for my usecases, I don't think I've ever used a semicolon in sum limits. Still, wrapping the argument in braces was the first and obvious (to me) thing I tried to protect arguments that contain the delimiter, and I was surprised that this didn't work. Maybe I'll go for ';' plus the workaround from the other answers (even though that might be overkill)
    – Wisperwind
    Dec 16 '18 at 13:05














6












6








6







So I'm trying to implement a COOL-style Sum macro which is supposed to support the following syntax:



Sum{ldots}  % -> sum ldots
Sum[i]{ldots} % -> sum_{i} ldots
Sum[i in I]{ldots} % -> sum_{i in I} ldots
Sum[i, 0, N]{ldots} % -> sum_{i=0}^{N} ldots
Sum[{i,j}, 0, N]{ldots} % -> sum_{i,j=0}^{N} ldots
Sum[{i,j,k}]{ldots} % -> sum_{i,j,k} ldots


The important bit is that I would like braces to protect commas in the first argument. The actual implementation is in expl3 with the user interface using xparse. Unfortunately, xparse appears to always strip braces inside arguments if they surround the whole argument such that this protection will not work in all cases, no matter what my internal code does. Looking at the docs, I couldn't find a way to prevent this.



I tried macros signatures of the forms



DeclareDocumentCommand Sum { s >{ SplitArgument{2}{,} } o m }
{ ... }
DeclareDocumentCommand Sum { s o m }
{ ... }


Am I missing something here, is there a (undocumented) way to make xparse not strip such braces short of circumventing xparse and implementing the interface manually (maybe using argument processors?)? If not, would this warrant a bug report/feature request at the latex github?










share|improve this question













So I'm trying to implement a COOL-style Sum macro which is supposed to support the following syntax:



Sum{ldots}  % -> sum ldots
Sum[i]{ldots} % -> sum_{i} ldots
Sum[i in I]{ldots} % -> sum_{i in I} ldots
Sum[i, 0, N]{ldots} % -> sum_{i=0}^{N} ldots
Sum[{i,j}, 0, N]{ldots} % -> sum_{i,j=0}^{N} ldots
Sum[{i,j,k}]{ldots} % -> sum_{i,j,k} ldots


The important bit is that I would like braces to protect commas in the first argument. The actual implementation is in expl3 with the user interface using xparse. Unfortunately, xparse appears to always strip braces inside arguments if they surround the whole argument such that this protection will not work in all cases, no matter what my internal code does. Looking at the docs, I couldn't find a way to prevent this.



I tried macros signatures of the forms



DeclareDocumentCommand Sum { s >{ SplitArgument{2}{,} } o m }
{ ... }
DeclareDocumentCommand Sum { s o m }
{ ... }


Am I missing something here, is there a (undocumented) way to make xparse not strip such braces short of circumventing xparse and implementing the interface manually (maybe using argument processors?)? If not, would this warrant a bug report/feature request at the latex github?







xparse






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 15 '18 at 13:37









WisperwindWisperwind

1676




1676












  • Not a solution: You could input Sum[{{i,j,k}}]{ldots}.
    – Skillmon
    Dec 15 '18 at 13:57






  • 3




    Why not simply using ; as delimiter? You would need no braces.
    – egreg
    Dec 15 '18 at 14:03












  • Using ; would likely work for my usecases, I don't think I've ever used a semicolon in sum limits. Still, wrapping the argument in braces was the first and obvious (to me) thing I tried to protect arguments that contain the delimiter, and I was surprised that this didn't work. Maybe I'll go for ';' plus the workaround from the other answers (even though that might be overkill)
    – Wisperwind
    Dec 16 '18 at 13:05


















  • Not a solution: You could input Sum[{{i,j,k}}]{ldots}.
    – Skillmon
    Dec 15 '18 at 13:57






  • 3




    Why not simply using ; as delimiter? You would need no braces.
    – egreg
    Dec 15 '18 at 14:03












  • Using ; would likely work for my usecases, I don't think I've ever used a semicolon in sum limits. Still, wrapping the argument in braces was the first and obvious (to me) thing I tried to protect arguments that contain the delimiter, and I was surprised that this didn't work. Maybe I'll go for ';' plus the workaround from the other answers (even though that might be overkill)
    – Wisperwind
    Dec 16 '18 at 13:05
















Not a solution: You could input Sum[{{i,j,k}}]{ldots}.
– Skillmon
Dec 15 '18 at 13:57




Not a solution: You could input Sum[{{i,j,k}}]{ldots}.
– Skillmon
Dec 15 '18 at 13:57




3




3




Why not simply using ; as delimiter? You would need no braces.
– egreg
Dec 15 '18 at 14:03






Why not simply using ; as delimiter? You would need no braces.
– egreg
Dec 15 '18 at 14:03














Using ; would likely work for my usecases, I don't think I've ever used a semicolon in sum limits. Still, wrapping the argument in braces was the first and obvious (to me) thing I tried to protect arguments that contain the delimiter, and I was surprised that this didn't work. Maybe I'll go for ';' plus the workaround from the other answers (even though that might be overkill)
– Wisperwind
Dec 16 '18 at 13:05




Using ; would likely work for my usecases, I don't think I've ever used a semicolon in sum limits. Still, wrapping the argument in braces was the first and obvious (to me) thing I tried to protect arguments that contain the delimiter, and I was surprised that this didn't work. Maybe I'll go for ';' plus the workaround from the other answers (even though that might be overkill)
– Wisperwind
Dec 16 '18 at 13:05










3 Answers
3






active

oldest

votes


















5














You can trick this by inserting another token after the opening bracket if there is one (proof of concept like answer). Replace Wisperwind_Sum_original_code:nnn with your original code to typeset the sum (including the handling of the optional star with IfBooleanTF).



documentclass{article}

usepackage{xparse}
ExplSyntaxOn
clist_new:N l_Wisperwind_clist
NewDocumentCommand Sum { s t[ }
{
IfBooleanTF { #2 }
{ Sum_two { #1 } [ use_none:n {} }
{ Sum_two { #1 } }
}
NewDocumentCommand Sum_two { m O{ use_none:n {} } m }
{
Wisperwind_Sum_original_code:non { #1 } { #2 } { #3 }
}
cs_new:Npn Wisperwind_Sum_original_code:nnn #1 #2 #3
{
sum
clist_set:Nn l_Wisperwind_clist { #2 }
int_case:nn { clist_count:N l_Wisperwind_clist }
{
{ 1 } { sb { clist_item:Nn l_Wisperwind_clist { c_one_int } } }
{ 2 }
{
sb { clist_item:Nn l_Wisperwind_clist { c_one_int } }
sp { clist_item:Nn l_Wisperwind_clist { 2 } }
}
{ 3 }
{
sb
{
clist_item:Nn l_Wisperwind_clist { c_one_int }
=
clist_item:Nn l_Wisperwind_clist { 2 }
}
sp { clist_item:Nn l_Wisperwind_clist { 3 } }
}
}
#3
}
cs_generate_variant:Nn Wisperwind_Sum_original_code:nnn { non }
ExplSyntaxOff

begin{document}
$Sum{ldots}$ % -> sum ldots
$Sum[i]{ldots}$ % -> sum_{i} ldots
$Sum[i in I]{ldots}$ % -> sum_{i in I} ldots
$Sum[i, 0, N]{ldots}$ % -> sum_{i=0}^{N} ldots
$Sum[{i,j}, 0, N]{ldots}$ % -> sum_{i,j=0}^{N} ldots
$Sum[{i,j,k}]{ldots}$ % -> sum_{i,j,k} ldots
end{document}


enter image description here






share|improve this answer























  • Thanks for this suggestion (although this is pretty much the 'hack' I had hoped to avoid)! The solution I had in mind would have been closer to @steven-b-segletes answer, but your code preserves the advanced parsing of nested optional arguments that xparse offers.
    – Wisperwind
    Dec 16 '18 at 12:55



















4














Here using LaTeX2e (see below for Plain TeX):



documentclass{article}
usepackage{listofitems}
makeatletter
newcommandSum{@ifnextchar[{Sumaux[@gobble}{sum}}
makeatother
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
begin{document}
[Sum{ldots} ]% -> sum ldots
[Sum[i]{ldots} ]% -> sum_{i} ldots
[Sum[i in I]{ldots} ]% -> sum_{i in I} ldots
[Sum[i, 0, N]{ldots} ]% -> sum_{i=0}^{N} ldots
[Sum[{i,j}, 0, N]{ldots} ]% -> sum_{i,j=0}^{N} ldots
[Sum[{i,j,k}]{ldots} ]% -> sum_{i,j,k} ldots
end{document}


enter image description here



This approach can also be implemented in Plain TeX:



input listofitems
defgobble#1{}
defSum{futureletnextdoSum}
defdoSum{ifx[next%
expandafterSumauxexpandafter[expandaftergobbleelsesumfi}
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
$$Sum{dots} $$% -> sum ldots
$$Sum[i]{ldots} $$% -> sum_{i} ldots
$$Sum[i in I]{ldots} $$% -> sum_{i in I} ldots
$$Sum[i, 0, N]{ldots} $$% -> sum_{i=0}^{N} ldots
$$Sum[{i,j}, 0, N]{ldots} $$% -> sum_{i,j=0}^{N} ldots
$$Sum[{i,j,k}]{ldots} $$% -> sum_{i,j,k} ldots
bye





share|improve this answer























  • Thanks for the input, I'm writing this using expl3 + xparse, though (obviously I could translate your code to expl3) and for the reason mentioned in another comment will likely prefer @Skillmon 's suggestion
    – Wisperwind
    Dec 16 '18 at 12:57



















3














The brace stripping is quite deliberate as newcommand-generated commands requires braces for the case



foo[{]}]{bar}


whereas xparse-generated ones do not. Without brace stripping,



foo[{bar}]


and



foo[bar]


could be treated differently.



In your case, you have a comma list with one entry. The obvious solution is to provide a second, empty, entry



Sum[{i,j},]{ldots}


as this is a no-op.






share|improve this answer

















  • 1




    I actually find this behavior unexpected AND annoying. I would prefer foo[{bar}] and foo[bar] to be (potentially) treated differently. But I also see the need, as in the initial case you present, to embrace the bracket.
    – Steven B. Segletes
    Dec 15 '18 at 16:45








  • 2




    @StevenB.Segletes I guess the reason is as (almost) always of historical nature. Since optional arguments created with newcommand behave this way (as well as those created with deffoo[#1]) it is the expected behaviour for optional arguments, because it always was this way.
    – Skillmon
    Dec 15 '18 at 16:47










  • @StevenB.Segletes As we are not changing the catcode of [/], the only way to have a TeX <balanced text> argument as an optional argument is to use a brace pair. Thus when the optional argument is exactly one balanced text we strip braces. It's the only way to handle stuff 'reasonably'.
    – Joseph Wright
    Dec 15 '18 at 18:17










  • @JosephWright I think I don't really understand what exactly wouldn't work without stripping braces. Wrt the first example, I guess you meant to say foo[bar[baz]]{test} does not require braces if defined through xparse, because foo[{]}]{bar} does. Is the reason mostly historical in order to match newcommand as @skillmon suggests? For most macros, I would expect additional braces not being stripped to not be an issue, thus this was also rather unexpected to me.
    – Wisperwind
    Dec 16 '18 at 12:51










  • The workaround you suggest is what I'm currently doing, but I'd prefer not to have such quirks in the user interface.
    – Wisperwind
    Dec 16 '18 at 12:52











Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "85"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f465970%2fprevent-xparse-from-stripping-braces%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









5














You can trick this by inserting another token after the opening bracket if there is one (proof of concept like answer). Replace Wisperwind_Sum_original_code:nnn with your original code to typeset the sum (including the handling of the optional star with IfBooleanTF).



documentclass{article}

usepackage{xparse}
ExplSyntaxOn
clist_new:N l_Wisperwind_clist
NewDocumentCommand Sum { s t[ }
{
IfBooleanTF { #2 }
{ Sum_two { #1 } [ use_none:n {} }
{ Sum_two { #1 } }
}
NewDocumentCommand Sum_two { m O{ use_none:n {} } m }
{
Wisperwind_Sum_original_code:non { #1 } { #2 } { #3 }
}
cs_new:Npn Wisperwind_Sum_original_code:nnn #1 #2 #3
{
sum
clist_set:Nn l_Wisperwind_clist { #2 }
int_case:nn { clist_count:N l_Wisperwind_clist }
{
{ 1 } { sb { clist_item:Nn l_Wisperwind_clist { c_one_int } } }
{ 2 }
{
sb { clist_item:Nn l_Wisperwind_clist { c_one_int } }
sp { clist_item:Nn l_Wisperwind_clist { 2 } }
}
{ 3 }
{
sb
{
clist_item:Nn l_Wisperwind_clist { c_one_int }
=
clist_item:Nn l_Wisperwind_clist { 2 }
}
sp { clist_item:Nn l_Wisperwind_clist { 3 } }
}
}
#3
}
cs_generate_variant:Nn Wisperwind_Sum_original_code:nnn { non }
ExplSyntaxOff

begin{document}
$Sum{ldots}$ % -> sum ldots
$Sum[i]{ldots}$ % -> sum_{i} ldots
$Sum[i in I]{ldots}$ % -> sum_{i in I} ldots
$Sum[i, 0, N]{ldots}$ % -> sum_{i=0}^{N} ldots
$Sum[{i,j}, 0, N]{ldots}$ % -> sum_{i,j=0}^{N} ldots
$Sum[{i,j,k}]{ldots}$ % -> sum_{i,j,k} ldots
end{document}


enter image description here






share|improve this answer























  • Thanks for this suggestion (although this is pretty much the 'hack' I had hoped to avoid)! The solution I had in mind would have been closer to @steven-b-segletes answer, but your code preserves the advanced parsing of nested optional arguments that xparse offers.
    – Wisperwind
    Dec 16 '18 at 12:55
















5














You can trick this by inserting another token after the opening bracket if there is one (proof of concept like answer). Replace Wisperwind_Sum_original_code:nnn with your original code to typeset the sum (including the handling of the optional star with IfBooleanTF).



documentclass{article}

usepackage{xparse}
ExplSyntaxOn
clist_new:N l_Wisperwind_clist
NewDocumentCommand Sum { s t[ }
{
IfBooleanTF { #2 }
{ Sum_two { #1 } [ use_none:n {} }
{ Sum_two { #1 } }
}
NewDocumentCommand Sum_two { m O{ use_none:n {} } m }
{
Wisperwind_Sum_original_code:non { #1 } { #2 } { #3 }
}
cs_new:Npn Wisperwind_Sum_original_code:nnn #1 #2 #3
{
sum
clist_set:Nn l_Wisperwind_clist { #2 }
int_case:nn { clist_count:N l_Wisperwind_clist }
{
{ 1 } { sb { clist_item:Nn l_Wisperwind_clist { c_one_int } } }
{ 2 }
{
sb { clist_item:Nn l_Wisperwind_clist { c_one_int } }
sp { clist_item:Nn l_Wisperwind_clist { 2 } }
}
{ 3 }
{
sb
{
clist_item:Nn l_Wisperwind_clist { c_one_int }
=
clist_item:Nn l_Wisperwind_clist { 2 }
}
sp { clist_item:Nn l_Wisperwind_clist { 3 } }
}
}
#3
}
cs_generate_variant:Nn Wisperwind_Sum_original_code:nnn { non }
ExplSyntaxOff

begin{document}
$Sum{ldots}$ % -> sum ldots
$Sum[i]{ldots}$ % -> sum_{i} ldots
$Sum[i in I]{ldots}$ % -> sum_{i in I} ldots
$Sum[i, 0, N]{ldots}$ % -> sum_{i=0}^{N} ldots
$Sum[{i,j}, 0, N]{ldots}$ % -> sum_{i,j=0}^{N} ldots
$Sum[{i,j,k}]{ldots}$ % -> sum_{i,j,k} ldots
end{document}


enter image description here






share|improve this answer























  • Thanks for this suggestion (although this is pretty much the 'hack' I had hoped to avoid)! The solution I had in mind would have been closer to @steven-b-segletes answer, but your code preserves the advanced parsing of nested optional arguments that xparse offers.
    – Wisperwind
    Dec 16 '18 at 12:55














5












5








5






You can trick this by inserting another token after the opening bracket if there is one (proof of concept like answer). Replace Wisperwind_Sum_original_code:nnn with your original code to typeset the sum (including the handling of the optional star with IfBooleanTF).



documentclass{article}

usepackage{xparse}
ExplSyntaxOn
clist_new:N l_Wisperwind_clist
NewDocumentCommand Sum { s t[ }
{
IfBooleanTF { #2 }
{ Sum_two { #1 } [ use_none:n {} }
{ Sum_two { #1 } }
}
NewDocumentCommand Sum_two { m O{ use_none:n {} } m }
{
Wisperwind_Sum_original_code:non { #1 } { #2 } { #3 }
}
cs_new:Npn Wisperwind_Sum_original_code:nnn #1 #2 #3
{
sum
clist_set:Nn l_Wisperwind_clist { #2 }
int_case:nn { clist_count:N l_Wisperwind_clist }
{
{ 1 } { sb { clist_item:Nn l_Wisperwind_clist { c_one_int } } }
{ 2 }
{
sb { clist_item:Nn l_Wisperwind_clist { c_one_int } }
sp { clist_item:Nn l_Wisperwind_clist { 2 } }
}
{ 3 }
{
sb
{
clist_item:Nn l_Wisperwind_clist { c_one_int }
=
clist_item:Nn l_Wisperwind_clist { 2 }
}
sp { clist_item:Nn l_Wisperwind_clist { 3 } }
}
}
#3
}
cs_generate_variant:Nn Wisperwind_Sum_original_code:nnn { non }
ExplSyntaxOff

begin{document}
$Sum{ldots}$ % -> sum ldots
$Sum[i]{ldots}$ % -> sum_{i} ldots
$Sum[i in I]{ldots}$ % -> sum_{i in I} ldots
$Sum[i, 0, N]{ldots}$ % -> sum_{i=0}^{N} ldots
$Sum[{i,j}, 0, N]{ldots}$ % -> sum_{i,j=0}^{N} ldots
$Sum[{i,j,k}]{ldots}$ % -> sum_{i,j,k} ldots
end{document}


enter image description here






share|improve this answer














You can trick this by inserting another token after the opening bracket if there is one (proof of concept like answer). Replace Wisperwind_Sum_original_code:nnn with your original code to typeset the sum (including the handling of the optional star with IfBooleanTF).



documentclass{article}

usepackage{xparse}
ExplSyntaxOn
clist_new:N l_Wisperwind_clist
NewDocumentCommand Sum { s t[ }
{
IfBooleanTF { #2 }
{ Sum_two { #1 } [ use_none:n {} }
{ Sum_two { #1 } }
}
NewDocumentCommand Sum_two { m O{ use_none:n {} } m }
{
Wisperwind_Sum_original_code:non { #1 } { #2 } { #3 }
}
cs_new:Npn Wisperwind_Sum_original_code:nnn #1 #2 #3
{
sum
clist_set:Nn l_Wisperwind_clist { #2 }
int_case:nn { clist_count:N l_Wisperwind_clist }
{
{ 1 } { sb { clist_item:Nn l_Wisperwind_clist { c_one_int } } }
{ 2 }
{
sb { clist_item:Nn l_Wisperwind_clist { c_one_int } }
sp { clist_item:Nn l_Wisperwind_clist { 2 } }
}
{ 3 }
{
sb
{
clist_item:Nn l_Wisperwind_clist { c_one_int }
=
clist_item:Nn l_Wisperwind_clist { 2 }
}
sp { clist_item:Nn l_Wisperwind_clist { 3 } }
}
}
#3
}
cs_generate_variant:Nn Wisperwind_Sum_original_code:nnn { non }
ExplSyntaxOff

begin{document}
$Sum{ldots}$ % -> sum ldots
$Sum[i]{ldots}$ % -> sum_{i} ldots
$Sum[i in I]{ldots}$ % -> sum_{i in I} ldots
$Sum[i, 0, N]{ldots}$ % -> sum_{i=0}^{N} ldots
$Sum[{i,j}, 0, N]{ldots}$ % -> sum_{i,j=0}^{N} ldots
$Sum[{i,j,k}]{ldots}$ % -> sum_{i,j,k} ldots
end{document}


enter image description here







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 15 '18 at 16:40

























answered Dec 15 '18 at 14:16









SkillmonSkillmon

21.3k11941




21.3k11941












  • Thanks for this suggestion (although this is pretty much the 'hack' I had hoped to avoid)! The solution I had in mind would have been closer to @steven-b-segletes answer, but your code preserves the advanced parsing of nested optional arguments that xparse offers.
    – Wisperwind
    Dec 16 '18 at 12:55


















  • Thanks for this suggestion (although this is pretty much the 'hack' I had hoped to avoid)! The solution I had in mind would have been closer to @steven-b-segletes answer, but your code preserves the advanced parsing of nested optional arguments that xparse offers.
    – Wisperwind
    Dec 16 '18 at 12:55
















Thanks for this suggestion (although this is pretty much the 'hack' I had hoped to avoid)! The solution I had in mind would have been closer to @steven-b-segletes answer, but your code preserves the advanced parsing of nested optional arguments that xparse offers.
– Wisperwind
Dec 16 '18 at 12:55




Thanks for this suggestion (although this is pretty much the 'hack' I had hoped to avoid)! The solution I had in mind would have been closer to @steven-b-segletes answer, but your code preserves the advanced parsing of nested optional arguments that xparse offers.
– Wisperwind
Dec 16 '18 at 12:55











4














Here using LaTeX2e (see below for Plain TeX):



documentclass{article}
usepackage{listofitems}
makeatletter
newcommandSum{@ifnextchar[{Sumaux[@gobble}{sum}}
makeatother
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
begin{document}
[Sum{ldots} ]% -> sum ldots
[Sum[i]{ldots} ]% -> sum_{i} ldots
[Sum[i in I]{ldots} ]% -> sum_{i in I} ldots
[Sum[i, 0, N]{ldots} ]% -> sum_{i=0}^{N} ldots
[Sum[{i,j}, 0, N]{ldots} ]% -> sum_{i,j=0}^{N} ldots
[Sum[{i,j,k}]{ldots} ]% -> sum_{i,j,k} ldots
end{document}


enter image description here



This approach can also be implemented in Plain TeX:



input listofitems
defgobble#1{}
defSum{futureletnextdoSum}
defdoSum{ifx[next%
expandafterSumauxexpandafter[expandaftergobbleelsesumfi}
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
$$Sum{dots} $$% -> sum ldots
$$Sum[i]{ldots} $$% -> sum_{i} ldots
$$Sum[i in I]{ldots} $$% -> sum_{i in I} ldots
$$Sum[i, 0, N]{ldots} $$% -> sum_{i=0}^{N} ldots
$$Sum[{i,j}, 0, N]{ldots} $$% -> sum_{i,j=0}^{N} ldots
$$Sum[{i,j,k}]{ldots} $$% -> sum_{i,j,k} ldots
bye





share|improve this answer























  • Thanks for the input, I'm writing this using expl3 + xparse, though (obviously I could translate your code to expl3) and for the reason mentioned in another comment will likely prefer @Skillmon 's suggestion
    – Wisperwind
    Dec 16 '18 at 12:57
















4














Here using LaTeX2e (see below for Plain TeX):



documentclass{article}
usepackage{listofitems}
makeatletter
newcommandSum{@ifnextchar[{Sumaux[@gobble}{sum}}
makeatother
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
begin{document}
[Sum{ldots} ]% -> sum ldots
[Sum[i]{ldots} ]% -> sum_{i} ldots
[Sum[i in I]{ldots} ]% -> sum_{i in I} ldots
[Sum[i, 0, N]{ldots} ]% -> sum_{i=0}^{N} ldots
[Sum[{i,j}, 0, N]{ldots} ]% -> sum_{i,j=0}^{N} ldots
[Sum[{i,j,k}]{ldots} ]% -> sum_{i,j,k} ldots
end{document}


enter image description here



This approach can also be implemented in Plain TeX:



input listofitems
defgobble#1{}
defSum{futureletnextdoSum}
defdoSum{ifx[next%
expandafterSumauxexpandafter[expandaftergobbleelsesumfi}
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
$$Sum{dots} $$% -> sum ldots
$$Sum[i]{ldots} $$% -> sum_{i} ldots
$$Sum[i in I]{ldots} $$% -> sum_{i in I} ldots
$$Sum[i, 0, N]{ldots} $$% -> sum_{i=0}^{N} ldots
$$Sum[{i,j}, 0, N]{ldots} $$% -> sum_{i,j=0}^{N} ldots
$$Sum[{i,j,k}]{ldots} $$% -> sum_{i,j,k} ldots
bye





share|improve this answer























  • Thanks for the input, I'm writing this using expl3 + xparse, though (obviously I could translate your code to expl3) and for the reason mentioned in another comment will likely prefer @Skillmon 's suggestion
    – Wisperwind
    Dec 16 '18 at 12:57














4












4








4






Here using LaTeX2e (see below for Plain TeX):



documentclass{article}
usepackage{listofitems}
makeatletter
newcommandSum{@ifnextchar[{Sumaux[@gobble}{sum}}
makeatother
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
begin{document}
[Sum{ldots} ]% -> sum ldots
[Sum[i]{ldots} ]% -> sum_{i} ldots
[Sum[i in I]{ldots} ]% -> sum_{i in I} ldots
[Sum[i, 0, N]{ldots} ]% -> sum_{i=0}^{N} ldots
[Sum[{i,j}, 0, N]{ldots} ]% -> sum_{i,j=0}^{N} ldots
[Sum[{i,j,k}]{ldots} ]% -> sum_{i,j,k} ldots
end{document}


enter image description here



This approach can also be implemented in Plain TeX:



input listofitems
defgobble#1{}
defSum{futureletnextdoSum}
defdoSum{ifx[next%
expandafterSumauxexpandafter[expandaftergobbleelsesumfi}
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
$$Sum{dots} $$% -> sum ldots
$$Sum[i]{ldots} $$% -> sum_{i} ldots
$$Sum[i in I]{ldots} $$% -> sum_{i in I} ldots
$$Sum[i, 0, N]{ldots} $$% -> sum_{i=0}^{N} ldots
$$Sum[{i,j}, 0, N]{ldots} $$% -> sum_{i,j=0}^{N} ldots
$$Sum[{i,j,k}]{ldots} $$% -> sum_{i,j,k} ldots
bye





share|improve this answer














Here using LaTeX2e (see below for Plain TeX):



documentclass{article}
usepackage{listofitems}
makeatletter
newcommandSum{@ifnextchar[{Sumaux[@gobble}{sum}}
makeatother
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
begin{document}
[Sum{ldots} ]% -> sum ldots
[Sum[i]{ldots} ]% -> sum_{i} ldots
[Sum[i in I]{ldots} ]% -> sum_{i in I} ldots
[Sum[i, 0, N]{ldots} ]% -> sum_{i=0}^{N} ldots
[Sum[{i,j}, 0, N]{ldots} ]% -> sum_{i,j=0}^{N} ldots
[Sum[{i,j,k}]{ldots} ]% -> sum_{i,j,k} ldots
end{document}


enter image description here



This approach can also be implemented in Plain TeX:



input listofitems
defgobble#1{}
defSum{futureletnextdoSum}
defdoSum{ifx[next%
expandafterSumauxexpandafter[expandaftergobbleelsesumfi}
defSumaux[#1]#2{
sum
setsepchar{,}
readlistsumargs{#1}
ifnumlistlensumargs>1relax
_{sumargs[1]=sumargs[2]}
ifnumlistlensumargs>2relax^sumargs[3]fi
else
_{sumargs[1]}
fi
#2
}
$$Sum{dots} $$% -> sum ldots
$$Sum[i]{ldots} $$% -> sum_{i} ldots
$$Sum[i in I]{ldots} $$% -> sum_{i in I} ldots
$$Sum[i, 0, N]{ldots} $$% -> sum_{i=0}^{N} ldots
$$Sum[{i,j}, 0, N]{ldots} $$% -> sum_{i,j=0}^{N} ldots
$$Sum[{i,j,k}]{ldots} $$% -> sum_{i,j,k} ldots
bye






share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 15 '18 at 18:05

























answered Dec 15 '18 at 14:55









Steven B. SegletesSteven B. Segletes

153k9193400




153k9193400












  • Thanks for the input, I'm writing this using expl3 + xparse, though (obviously I could translate your code to expl3) and for the reason mentioned in another comment will likely prefer @Skillmon 's suggestion
    – Wisperwind
    Dec 16 '18 at 12:57


















  • Thanks for the input, I'm writing this using expl3 + xparse, though (obviously I could translate your code to expl3) and for the reason mentioned in another comment will likely prefer @Skillmon 's suggestion
    – Wisperwind
    Dec 16 '18 at 12:57
















Thanks for the input, I'm writing this using expl3 + xparse, though (obviously I could translate your code to expl3) and for the reason mentioned in another comment will likely prefer @Skillmon 's suggestion
– Wisperwind
Dec 16 '18 at 12:57




Thanks for the input, I'm writing this using expl3 + xparse, though (obviously I could translate your code to expl3) and for the reason mentioned in another comment will likely prefer @Skillmon 's suggestion
– Wisperwind
Dec 16 '18 at 12:57











3














The brace stripping is quite deliberate as newcommand-generated commands requires braces for the case



foo[{]}]{bar}


whereas xparse-generated ones do not. Without brace stripping,



foo[{bar}]


and



foo[bar]


could be treated differently.



In your case, you have a comma list with one entry. The obvious solution is to provide a second, empty, entry



Sum[{i,j},]{ldots}


as this is a no-op.






share|improve this answer

















  • 1




    I actually find this behavior unexpected AND annoying. I would prefer foo[{bar}] and foo[bar] to be (potentially) treated differently. But I also see the need, as in the initial case you present, to embrace the bracket.
    – Steven B. Segletes
    Dec 15 '18 at 16:45








  • 2




    @StevenB.Segletes I guess the reason is as (almost) always of historical nature. Since optional arguments created with newcommand behave this way (as well as those created with deffoo[#1]) it is the expected behaviour for optional arguments, because it always was this way.
    – Skillmon
    Dec 15 '18 at 16:47










  • @StevenB.Segletes As we are not changing the catcode of [/], the only way to have a TeX <balanced text> argument as an optional argument is to use a brace pair. Thus when the optional argument is exactly one balanced text we strip braces. It's the only way to handle stuff 'reasonably'.
    – Joseph Wright
    Dec 15 '18 at 18:17










  • @JosephWright I think I don't really understand what exactly wouldn't work without stripping braces. Wrt the first example, I guess you meant to say foo[bar[baz]]{test} does not require braces if defined through xparse, because foo[{]}]{bar} does. Is the reason mostly historical in order to match newcommand as @skillmon suggests? For most macros, I would expect additional braces not being stripped to not be an issue, thus this was also rather unexpected to me.
    – Wisperwind
    Dec 16 '18 at 12:51










  • The workaround you suggest is what I'm currently doing, but I'd prefer not to have such quirks in the user interface.
    – Wisperwind
    Dec 16 '18 at 12:52
















3














The brace stripping is quite deliberate as newcommand-generated commands requires braces for the case



foo[{]}]{bar}


whereas xparse-generated ones do not. Without brace stripping,



foo[{bar}]


and



foo[bar]


could be treated differently.



In your case, you have a comma list with one entry. The obvious solution is to provide a second, empty, entry



Sum[{i,j},]{ldots}


as this is a no-op.






share|improve this answer

















  • 1




    I actually find this behavior unexpected AND annoying. I would prefer foo[{bar}] and foo[bar] to be (potentially) treated differently. But I also see the need, as in the initial case you present, to embrace the bracket.
    – Steven B. Segletes
    Dec 15 '18 at 16:45








  • 2




    @StevenB.Segletes I guess the reason is as (almost) always of historical nature. Since optional arguments created with newcommand behave this way (as well as those created with deffoo[#1]) it is the expected behaviour for optional arguments, because it always was this way.
    – Skillmon
    Dec 15 '18 at 16:47










  • @StevenB.Segletes As we are not changing the catcode of [/], the only way to have a TeX <balanced text> argument as an optional argument is to use a brace pair. Thus when the optional argument is exactly one balanced text we strip braces. It's the only way to handle stuff 'reasonably'.
    – Joseph Wright
    Dec 15 '18 at 18:17










  • @JosephWright I think I don't really understand what exactly wouldn't work without stripping braces. Wrt the first example, I guess you meant to say foo[bar[baz]]{test} does not require braces if defined through xparse, because foo[{]}]{bar} does. Is the reason mostly historical in order to match newcommand as @skillmon suggests? For most macros, I would expect additional braces not being stripped to not be an issue, thus this was also rather unexpected to me.
    – Wisperwind
    Dec 16 '18 at 12:51










  • The workaround you suggest is what I'm currently doing, but I'd prefer not to have such quirks in the user interface.
    – Wisperwind
    Dec 16 '18 at 12:52














3












3








3






The brace stripping is quite deliberate as newcommand-generated commands requires braces for the case



foo[{]}]{bar}


whereas xparse-generated ones do not. Without brace stripping,



foo[{bar}]


and



foo[bar]


could be treated differently.



In your case, you have a comma list with one entry. The obvious solution is to provide a second, empty, entry



Sum[{i,j},]{ldots}


as this is a no-op.






share|improve this answer












The brace stripping is quite deliberate as newcommand-generated commands requires braces for the case



foo[{]}]{bar}


whereas xparse-generated ones do not. Without brace stripping,



foo[{bar}]


and



foo[bar]


could be treated differently.



In your case, you have a comma list with one entry. The obvious solution is to provide a second, empty, entry



Sum[{i,j},]{ldots}


as this is a no-op.







share|improve this answer












share|improve this answer



share|improve this answer










answered Dec 15 '18 at 15:59









Joseph WrightJoseph Wright

202k21555882




202k21555882








  • 1




    I actually find this behavior unexpected AND annoying. I would prefer foo[{bar}] and foo[bar] to be (potentially) treated differently. But I also see the need, as in the initial case you present, to embrace the bracket.
    – Steven B. Segletes
    Dec 15 '18 at 16:45








  • 2




    @StevenB.Segletes I guess the reason is as (almost) always of historical nature. Since optional arguments created with newcommand behave this way (as well as those created with deffoo[#1]) it is the expected behaviour for optional arguments, because it always was this way.
    – Skillmon
    Dec 15 '18 at 16:47










  • @StevenB.Segletes As we are not changing the catcode of [/], the only way to have a TeX <balanced text> argument as an optional argument is to use a brace pair. Thus when the optional argument is exactly one balanced text we strip braces. It's the only way to handle stuff 'reasonably'.
    – Joseph Wright
    Dec 15 '18 at 18:17










  • @JosephWright I think I don't really understand what exactly wouldn't work without stripping braces. Wrt the first example, I guess you meant to say foo[bar[baz]]{test} does not require braces if defined through xparse, because foo[{]}]{bar} does. Is the reason mostly historical in order to match newcommand as @skillmon suggests? For most macros, I would expect additional braces not being stripped to not be an issue, thus this was also rather unexpected to me.
    – Wisperwind
    Dec 16 '18 at 12:51










  • The workaround you suggest is what I'm currently doing, but I'd prefer not to have such quirks in the user interface.
    – Wisperwind
    Dec 16 '18 at 12:52














  • 1




    I actually find this behavior unexpected AND annoying. I would prefer foo[{bar}] and foo[bar] to be (potentially) treated differently. But I also see the need, as in the initial case you present, to embrace the bracket.
    – Steven B. Segletes
    Dec 15 '18 at 16:45








  • 2




    @StevenB.Segletes I guess the reason is as (almost) always of historical nature. Since optional arguments created with newcommand behave this way (as well as those created with deffoo[#1]) it is the expected behaviour for optional arguments, because it always was this way.
    – Skillmon
    Dec 15 '18 at 16:47










  • @StevenB.Segletes As we are not changing the catcode of [/], the only way to have a TeX <balanced text> argument as an optional argument is to use a brace pair. Thus when the optional argument is exactly one balanced text we strip braces. It's the only way to handle stuff 'reasonably'.
    – Joseph Wright
    Dec 15 '18 at 18:17










  • @JosephWright I think I don't really understand what exactly wouldn't work without stripping braces. Wrt the first example, I guess you meant to say foo[bar[baz]]{test} does not require braces if defined through xparse, because foo[{]}]{bar} does. Is the reason mostly historical in order to match newcommand as @skillmon suggests? For most macros, I would expect additional braces not being stripped to not be an issue, thus this was also rather unexpected to me.
    – Wisperwind
    Dec 16 '18 at 12:51










  • The workaround you suggest is what I'm currently doing, but I'd prefer not to have such quirks in the user interface.
    – Wisperwind
    Dec 16 '18 at 12:52








1




1




I actually find this behavior unexpected AND annoying. I would prefer foo[{bar}] and foo[bar] to be (potentially) treated differently. But I also see the need, as in the initial case you present, to embrace the bracket.
– Steven B. Segletes
Dec 15 '18 at 16:45






I actually find this behavior unexpected AND annoying. I would prefer foo[{bar}] and foo[bar] to be (potentially) treated differently. But I also see the need, as in the initial case you present, to embrace the bracket.
– Steven B. Segletes
Dec 15 '18 at 16:45






2




2




@StevenB.Segletes I guess the reason is as (almost) always of historical nature. Since optional arguments created with newcommand behave this way (as well as those created with deffoo[#1]) it is the expected behaviour for optional arguments, because it always was this way.
– Skillmon
Dec 15 '18 at 16:47




@StevenB.Segletes I guess the reason is as (almost) always of historical nature. Since optional arguments created with newcommand behave this way (as well as those created with deffoo[#1]) it is the expected behaviour for optional arguments, because it always was this way.
– Skillmon
Dec 15 '18 at 16:47












@StevenB.Segletes As we are not changing the catcode of [/], the only way to have a TeX <balanced text> argument as an optional argument is to use a brace pair. Thus when the optional argument is exactly one balanced text we strip braces. It's the only way to handle stuff 'reasonably'.
– Joseph Wright
Dec 15 '18 at 18:17




@StevenB.Segletes As we are not changing the catcode of [/], the only way to have a TeX <balanced text> argument as an optional argument is to use a brace pair. Thus when the optional argument is exactly one balanced text we strip braces. It's the only way to handle stuff 'reasonably'.
– Joseph Wright
Dec 15 '18 at 18:17












@JosephWright I think I don't really understand what exactly wouldn't work without stripping braces. Wrt the first example, I guess you meant to say foo[bar[baz]]{test} does not require braces if defined through xparse, because foo[{]}]{bar} does. Is the reason mostly historical in order to match newcommand as @skillmon suggests? For most macros, I would expect additional braces not being stripped to not be an issue, thus this was also rather unexpected to me.
– Wisperwind
Dec 16 '18 at 12:51




@JosephWright I think I don't really understand what exactly wouldn't work without stripping braces. Wrt the first example, I guess you meant to say foo[bar[baz]]{test} does not require braces if defined through xparse, because foo[{]}]{bar} does. Is the reason mostly historical in order to match newcommand as @skillmon suggests? For most macros, I would expect additional braces not being stripped to not be an issue, thus this was also rather unexpected to me.
– Wisperwind
Dec 16 '18 at 12:51












The workaround you suggest is what I'm currently doing, but I'd prefer not to have such quirks in the user interface.
– Wisperwind
Dec 16 '18 at 12:52




The workaround you suggest is what I'm currently doing, but I'd prefer not to have such quirks in the user interface.
– Wisperwind
Dec 16 '18 at 12:52


















draft saved

draft discarded




















































Thanks for contributing an answer to TeX - LaTeX Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f465970%2fprevent-xparse-from-stripping-braces%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Plaza Victoria

Puebla de Zaragoza

Musa