Check if macro is fully expandable











up vote
2
down vote

favorite












Question



Is there a way to check whether a macro is fully expandable (or rather "safe in an expansion-only context" [1])?



Consider this code:



defa{Just a string}
defb{a}
defc{defunsafe}
defd{c}


How could I check which of the macros (a-d) are safe in an expansion-only context? By looking at them I know that a and b are whereas c and d are not but if I wanted to know the same for a macro I haven't written myself this could get quite useful.





Background



I am working on a way to detect whether some input is a valid number in PGF. For this I developed this approach which makes use of passing the input into pgfmathfloatparsenumber.

The problem I have run into is that said macro appears to somehow manages to expand the input until there is an error (if the input is in fact not safe in an expansion-only-context). I tried using protected, noexpand and similar but somehow PGF manages to circumvent those.



So the idea is to check whether the input is safe before actually passing it to PGF. The problem is: I don't know how I'd go about that...










share|improve this question


















  • 4




    you can't :-)...
    – David Carlisle
    1 hour ago










  • Well too bad... :(
    – Raven
    1 hour ago






  • 4




    well you can always do something of course, in the example you give it would be hard in general to avoid an undefined command error on that input, if you defined unsafe first then the edef would give something bad but would probably not give an error during the actual edef, such cases you can probably detect. similarly if you have edeffoo{ {mbox} } you are going to get a low level parse error if you expand mbox and it hits the } it woul dbe verh hard to avoid such errors if you allow bad input
    – David Carlisle
    1 hour ago












  • if you know in advance that the thing must expand say to some digits, you could try romannumeral-`0 triggered expansion, then examine first token if a digit ok remove and repeat and do repetitively until either nothing is left or you hit some unexpandable token which is not a digit. You have to detect case of braces etc... The idea here is that edef can cause errors if your material is not expandable, but "full-first" expansion will not.
    – jfbu
    1 hour ago






  • 1




    No, you misunderstood. I said "if the thing must expand say to some digits". If letters also are allowed then you only have to take that into account. The point is that if you know in advance what must be the full expansion outcome, then you can check it.
    – jfbu
    1 hour ago















up vote
2
down vote

favorite












Question



Is there a way to check whether a macro is fully expandable (or rather "safe in an expansion-only context" [1])?



Consider this code:



defa{Just a string}
defb{a}
defc{defunsafe}
defd{c}


How could I check which of the macros (a-d) are safe in an expansion-only context? By looking at them I know that a and b are whereas c and d are not but if I wanted to know the same for a macro I haven't written myself this could get quite useful.





Background



I am working on a way to detect whether some input is a valid number in PGF. For this I developed this approach which makes use of passing the input into pgfmathfloatparsenumber.

The problem I have run into is that said macro appears to somehow manages to expand the input until there is an error (if the input is in fact not safe in an expansion-only-context). I tried using protected, noexpand and similar but somehow PGF manages to circumvent those.



So the idea is to check whether the input is safe before actually passing it to PGF. The problem is: I don't know how I'd go about that...










share|improve this question


















  • 4




    you can't :-)...
    – David Carlisle
    1 hour ago










  • Well too bad... :(
    – Raven
    1 hour ago






  • 4




    well you can always do something of course, in the example you give it would be hard in general to avoid an undefined command error on that input, if you defined unsafe first then the edef would give something bad but would probably not give an error during the actual edef, such cases you can probably detect. similarly if you have edeffoo{ {mbox} } you are going to get a low level parse error if you expand mbox and it hits the } it woul dbe verh hard to avoid such errors if you allow bad input
    – David Carlisle
    1 hour ago












  • if you know in advance that the thing must expand say to some digits, you could try romannumeral-`0 triggered expansion, then examine first token if a digit ok remove and repeat and do repetitively until either nothing is left or you hit some unexpandable token which is not a digit. You have to detect case of braces etc... The idea here is that edef can cause errors if your material is not expandable, but "full-first" expansion will not.
    – jfbu
    1 hour ago






  • 1




    No, you misunderstood. I said "if the thing must expand say to some digits". If letters also are allowed then you only have to take that into account. The point is that if you know in advance what must be the full expansion outcome, then you can check it.
    – jfbu
    1 hour ago













up vote
2
down vote

favorite









up vote
2
down vote

favorite











Question



Is there a way to check whether a macro is fully expandable (or rather "safe in an expansion-only context" [1])?



Consider this code:



defa{Just a string}
defb{a}
defc{defunsafe}
defd{c}


How could I check which of the macros (a-d) are safe in an expansion-only context? By looking at them I know that a and b are whereas c and d are not but if I wanted to know the same for a macro I haven't written myself this could get quite useful.





Background



I am working on a way to detect whether some input is a valid number in PGF. For this I developed this approach which makes use of passing the input into pgfmathfloatparsenumber.

The problem I have run into is that said macro appears to somehow manages to expand the input until there is an error (if the input is in fact not safe in an expansion-only-context). I tried using protected, noexpand and similar but somehow PGF manages to circumvent those.



So the idea is to check whether the input is safe before actually passing it to PGF. The problem is: I don't know how I'd go about that...










share|improve this question













Question



Is there a way to check whether a macro is fully expandable (or rather "safe in an expansion-only context" [1])?



Consider this code:



defa{Just a string}
defb{a}
defc{defunsafe}
defd{c}


How could I check which of the macros (a-d) are safe in an expansion-only context? By looking at them I know that a and b are whereas c and d are not but if I wanted to know the same for a macro I haven't written myself this could get quite useful.





Background



I am working on a way to detect whether some input is a valid number in PGF. For this I developed this approach which makes use of passing the input into pgfmathfloatparsenumber.

The problem I have run into is that said macro appears to somehow manages to expand the input until there is an error (if the input is in fact not safe in an expansion-only-context). I tried using protected, noexpand and similar but somehow PGF manages to circumvent those.



So the idea is to check whether the input is safe before actually passing it to PGF. The problem is: I don't know how I'd go about that...







tex-core expansion






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 1 hour ago









Raven

551110




551110








  • 4




    you can't :-)...
    – David Carlisle
    1 hour ago










  • Well too bad... :(
    – Raven
    1 hour ago






  • 4




    well you can always do something of course, in the example you give it would be hard in general to avoid an undefined command error on that input, if you defined unsafe first then the edef would give something bad but would probably not give an error during the actual edef, such cases you can probably detect. similarly if you have edeffoo{ {mbox} } you are going to get a low level parse error if you expand mbox and it hits the } it woul dbe verh hard to avoid such errors if you allow bad input
    – David Carlisle
    1 hour ago












  • if you know in advance that the thing must expand say to some digits, you could try romannumeral-`0 triggered expansion, then examine first token if a digit ok remove and repeat and do repetitively until either nothing is left or you hit some unexpandable token which is not a digit. You have to detect case of braces etc... The idea here is that edef can cause errors if your material is not expandable, but "full-first" expansion will not.
    – jfbu
    1 hour ago






  • 1




    No, you misunderstood. I said "if the thing must expand say to some digits". If letters also are allowed then you only have to take that into account. The point is that if you know in advance what must be the full expansion outcome, then you can check it.
    – jfbu
    1 hour ago














  • 4




    you can't :-)...
    – David Carlisle
    1 hour ago










  • Well too bad... :(
    – Raven
    1 hour ago






  • 4




    well you can always do something of course, in the example you give it would be hard in general to avoid an undefined command error on that input, if you defined unsafe first then the edef would give something bad but would probably not give an error during the actual edef, such cases you can probably detect. similarly if you have edeffoo{ {mbox} } you are going to get a low level parse error if you expand mbox and it hits the } it woul dbe verh hard to avoid such errors if you allow bad input
    – David Carlisle
    1 hour ago












  • if you know in advance that the thing must expand say to some digits, you could try romannumeral-`0 triggered expansion, then examine first token if a digit ok remove and repeat and do repetitively until either nothing is left or you hit some unexpandable token which is not a digit. You have to detect case of braces etc... The idea here is that edef can cause errors if your material is not expandable, but "full-first" expansion will not.
    – jfbu
    1 hour ago






  • 1




    No, you misunderstood. I said "if the thing must expand say to some digits". If letters also are allowed then you only have to take that into account. The point is that if you know in advance what must be the full expansion outcome, then you can check it.
    – jfbu
    1 hour ago








4




4




you can't :-)...
– David Carlisle
1 hour ago




you can't :-)...
– David Carlisle
1 hour ago












Well too bad... :(
– Raven
1 hour ago




Well too bad... :(
– Raven
1 hour ago




4




4




well you can always do something of course, in the example you give it would be hard in general to avoid an undefined command error on that input, if you defined unsafe first then the edef would give something bad but would probably not give an error during the actual edef, such cases you can probably detect. similarly if you have edeffoo{ {mbox} } you are going to get a low level parse error if you expand mbox and it hits the } it woul dbe verh hard to avoid such errors if you allow bad input
– David Carlisle
1 hour ago






well you can always do something of course, in the example you give it would be hard in general to avoid an undefined command error on that input, if you defined unsafe first then the edef would give something bad but would probably not give an error during the actual edef, such cases you can probably detect. similarly if you have edeffoo{ {mbox} } you are going to get a low level parse error if you expand mbox and it hits the } it woul dbe verh hard to avoid such errors if you allow bad input
– David Carlisle
1 hour ago














if you know in advance that the thing must expand say to some digits, you could try romannumeral-`0 triggered expansion, then examine first token if a digit ok remove and repeat and do repetitively until either nothing is left or you hit some unexpandable token which is not a digit. You have to detect case of braces etc... The idea here is that edef can cause errors if your material is not expandable, but "full-first" expansion will not.
– jfbu
1 hour ago




if you know in advance that the thing must expand say to some digits, you could try romannumeral-`0 triggered expansion, then examine first token if a digit ok remove and repeat and do repetitively until either nothing is left or you hit some unexpandable token which is not a digit. You have to detect case of braces etc... The idea here is that edef can cause errors if your material is not expandable, but "full-first" expansion will not.
– jfbu
1 hour ago




1




1




No, you misunderstood. I said "if the thing must expand say to some digits". If letters also are allowed then you only have to take that into account. The point is that if you know in advance what must be the full expansion outcome, then you can check it.
– jfbu
1 hour ago




No, you misunderstood. I said "if the thing must expand say to some digits". If letters also are allowed then you only have to take that into account. The point is that if you know in advance what must be the full expansion outcome, then you can check it.
– jfbu
1 hour ago










1 Answer
1






active

oldest

votes

















up vote
4
down vote













Did I hear someone say that it's not possible?



The following defines ifexpandable which checks whether a token is expandable (actually you can also give it a list of tokens and it checks whether all of them are expandable). I don't know whether this has any side effects. Requires LuaTeX.



defifexpandable#1{%
directlua{
local t = token.scan_toks(false, "expand")
local b = true
for n,v in ipairs(t) do
b = b and v.expandable
end
if b then
tex.sprint("string\iftrue")
else
tex.sprint("string\iffalse")
end
}{#1}
}

deffoo{{hbox}}
ifexpandablefoo
expandable
else
not expandable
fi

bye


enter image description here






share|improve this answer























  • What about something like deffoo{{hbox}}ifexpandablefoo?
    – Joseph Wright
    52 mins ago










  • @JosephWright foo is expandable, i.e. you have to expand it once and ask ifexpandable again. I tried to expand step-wise with token.expand but quickly realised that I actually have no idea what this function is doing.
    – Henri Menke
    51 mins ago








  • 1




    I think the OP query is not testing one token but testing an entire input which may conceivably be foo Ebar for example.
    – jfbu
    49 mins ago










  • @jfbu Fixed. I just found that scan_toks takes arguments, one of them is to expand the tokens.
    – Henri Menke
    41 mins ago






  • 1




    blindly +1ing :)
    – jfbu
    41 mins ago











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',
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%2f464646%2fcheck-if-macro-is-fully-expandable%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
4
down vote













Did I hear someone say that it's not possible?



The following defines ifexpandable which checks whether a token is expandable (actually you can also give it a list of tokens and it checks whether all of them are expandable). I don't know whether this has any side effects. Requires LuaTeX.



defifexpandable#1{%
directlua{
local t = token.scan_toks(false, "expand")
local b = true
for n,v in ipairs(t) do
b = b and v.expandable
end
if b then
tex.sprint("string\iftrue")
else
tex.sprint("string\iffalse")
end
}{#1}
}

deffoo{{hbox}}
ifexpandablefoo
expandable
else
not expandable
fi

bye


enter image description here






share|improve this answer























  • What about something like deffoo{{hbox}}ifexpandablefoo?
    – Joseph Wright
    52 mins ago










  • @JosephWright foo is expandable, i.e. you have to expand it once and ask ifexpandable again. I tried to expand step-wise with token.expand but quickly realised that I actually have no idea what this function is doing.
    – Henri Menke
    51 mins ago








  • 1




    I think the OP query is not testing one token but testing an entire input which may conceivably be foo Ebar for example.
    – jfbu
    49 mins ago










  • @jfbu Fixed. I just found that scan_toks takes arguments, one of them is to expand the tokens.
    – Henri Menke
    41 mins ago






  • 1




    blindly +1ing :)
    – jfbu
    41 mins ago















up vote
4
down vote













Did I hear someone say that it's not possible?



The following defines ifexpandable which checks whether a token is expandable (actually you can also give it a list of tokens and it checks whether all of them are expandable). I don't know whether this has any side effects. Requires LuaTeX.



defifexpandable#1{%
directlua{
local t = token.scan_toks(false, "expand")
local b = true
for n,v in ipairs(t) do
b = b and v.expandable
end
if b then
tex.sprint("string\iftrue")
else
tex.sprint("string\iffalse")
end
}{#1}
}

deffoo{{hbox}}
ifexpandablefoo
expandable
else
not expandable
fi

bye


enter image description here






share|improve this answer























  • What about something like deffoo{{hbox}}ifexpandablefoo?
    – Joseph Wright
    52 mins ago










  • @JosephWright foo is expandable, i.e. you have to expand it once and ask ifexpandable again. I tried to expand step-wise with token.expand but quickly realised that I actually have no idea what this function is doing.
    – Henri Menke
    51 mins ago








  • 1




    I think the OP query is not testing one token but testing an entire input which may conceivably be foo Ebar for example.
    – jfbu
    49 mins ago










  • @jfbu Fixed. I just found that scan_toks takes arguments, one of them is to expand the tokens.
    – Henri Menke
    41 mins ago






  • 1




    blindly +1ing :)
    – jfbu
    41 mins ago













up vote
4
down vote










up vote
4
down vote









Did I hear someone say that it's not possible?



The following defines ifexpandable which checks whether a token is expandable (actually you can also give it a list of tokens and it checks whether all of them are expandable). I don't know whether this has any side effects. Requires LuaTeX.



defifexpandable#1{%
directlua{
local t = token.scan_toks(false, "expand")
local b = true
for n,v in ipairs(t) do
b = b and v.expandable
end
if b then
tex.sprint("string\iftrue")
else
tex.sprint("string\iffalse")
end
}{#1}
}

deffoo{{hbox}}
ifexpandablefoo
expandable
else
not expandable
fi

bye


enter image description here






share|improve this answer














Did I hear someone say that it's not possible?



The following defines ifexpandable which checks whether a token is expandable (actually you can also give it a list of tokens and it checks whether all of them are expandable). I don't know whether this has any side effects. Requires LuaTeX.



defifexpandable#1{%
directlua{
local t = token.scan_toks(false, "expand")
local b = true
for n,v in ipairs(t) do
b = b and v.expandable
end
if b then
tex.sprint("string\iftrue")
else
tex.sprint("string\iffalse")
end
}{#1}
}

deffoo{{hbox}}
ifexpandablefoo
expandable
else
not expandable
fi

bye


enter image description here







share|improve this answer














share|improve this answer



share|improve this answer








edited 39 mins ago

























answered 53 mins ago









Henri Menke

68.8k7153257




68.8k7153257












  • What about something like deffoo{{hbox}}ifexpandablefoo?
    – Joseph Wright
    52 mins ago










  • @JosephWright foo is expandable, i.e. you have to expand it once and ask ifexpandable again. I tried to expand step-wise with token.expand but quickly realised that I actually have no idea what this function is doing.
    – Henri Menke
    51 mins ago








  • 1




    I think the OP query is not testing one token but testing an entire input which may conceivably be foo Ebar for example.
    – jfbu
    49 mins ago










  • @jfbu Fixed. I just found that scan_toks takes arguments, one of them is to expand the tokens.
    – Henri Menke
    41 mins ago






  • 1




    blindly +1ing :)
    – jfbu
    41 mins ago


















  • What about something like deffoo{{hbox}}ifexpandablefoo?
    – Joseph Wright
    52 mins ago










  • @JosephWright foo is expandable, i.e. you have to expand it once and ask ifexpandable again. I tried to expand step-wise with token.expand but quickly realised that I actually have no idea what this function is doing.
    – Henri Menke
    51 mins ago








  • 1




    I think the OP query is not testing one token but testing an entire input which may conceivably be foo Ebar for example.
    – jfbu
    49 mins ago










  • @jfbu Fixed. I just found that scan_toks takes arguments, one of them is to expand the tokens.
    – Henri Menke
    41 mins ago






  • 1




    blindly +1ing :)
    – jfbu
    41 mins ago
















What about something like deffoo{{hbox}}ifexpandablefoo?
– Joseph Wright
52 mins ago




What about something like deffoo{{hbox}}ifexpandablefoo?
– Joseph Wright
52 mins ago












@JosephWright foo is expandable, i.e. you have to expand it once and ask ifexpandable again. I tried to expand step-wise with token.expand but quickly realised that I actually have no idea what this function is doing.
– Henri Menke
51 mins ago






@JosephWright foo is expandable, i.e. you have to expand it once and ask ifexpandable again. I tried to expand step-wise with token.expand but quickly realised that I actually have no idea what this function is doing.
– Henri Menke
51 mins ago






1




1




I think the OP query is not testing one token but testing an entire input which may conceivably be foo Ebar for example.
– jfbu
49 mins ago




I think the OP query is not testing one token but testing an entire input which may conceivably be foo Ebar for example.
– jfbu
49 mins ago












@jfbu Fixed. I just found that scan_toks takes arguments, one of them is to expand the tokens.
– Henri Menke
41 mins ago




@jfbu Fixed. I just found that scan_toks takes arguments, one of them is to expand the tokens.
– Henri Menke
41 mins ago




1




1




blindly +1ing :)
– jfbu
41 mins ago




blindly +1ing :)
– jfbu
41 mins ago


















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%2f464646%2fcheck-if-macro-is-fully-expandable%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

What visual should I use to simply compare current year value vs last year in Power BI desktop

Alexandru Averescu

Trompette piccolo