Bookmark and Share

Notice: On April 23, 2014, Statalist moved from an email list to a forum, based at statalist.org.


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: st: Detecting a macro expansion error


From   Nick Cox <njcoxstata@gmail.com>
To   statalist@hsphsun2.harvard.edu
Subject   Re: st: Detecting a macro expansion error
Date   Mon, 2 Jan 2012 10:20:55 +0000

Sorry, but I am not closer to understanding your aim. It might be
clearer if you gave a complete example of a program and of a tricky
thing with macros that a user might reasonably want to do that you
want to indulge, although I am not confident that this vague
description matches your perceived problem.

I don't know quite what a macro expansion error would look like as far
as you are concerned, so I don't know how to suggest catching it.

A side-issue is that it is a bad idea to change Stata's own code, in
this case -levelsof-. Clone and experiment, by all means.

Nick

On Mon, Jan 2, 2012 at 3:22 AM, Matthew White <mwhite@poverty-action.org> wrote:
> Hi Nick,
>
>> Local macros are Stata entities. Reading them into Mata to compare
>> them and writing back results to Stata looks unnecessarily roundabout.
> I imagine there has to be a better way, I just don't know what it is.
> There doesn't seem to be an easy way to detect macro expansion errors
> in Stata, so I'm using Mata to parse a string for expansion operators,
> and then evaluating the expansions in Stata to see if they produce
> errors. I tend to prefer Mata over Stata for string parsing when the
> string might be long (more than 245 characters) or when the
> characteristics of the string are unknown (e.g., whether the string
> should be enclosed by simple or compound quotes). Here, I can't think
> of a good way to get around the Mata, even though the Mata is dealing
> with a Stata entity, macro expansion.
>
>> I can't see the logic of your first block of code. Local macro -temp-> is defined as a copy of local macro -str-. This can't fail as it is> legal whether -str- is empty or not, so I can't see the point of> -capture-. I don't see why you think that -capture- suppresses macro> expansion.
>
> `temp' is the same as `str' as long as `str' doesn't contain delayed
> macro expansions. For example:
> local str \`='
> local temp "`str'"
> macro dir
> Here, `str' and `temp' have come apart. Note the difference between:
> local temp "`str'"
> and:
> local temp : copy local str
>
> Then I want to use -capture- to suppress macro expansion error
> messages, not the macro expansion itself. For example:
> local str \`='
> local temp "`str'"
> produces a macro expansion error message, but:
> local str \`='
> capture {
>    local temp "`str'"
> }
> does not.
> Note that
> capture local temp "`str'"
> and
> quietly {
>    local temp "`str'"
> }
> both fail to suppress the error message.
>
>> I have a prejudice that delaying macro expansion is almost always
>> unnecessary, developed at length on Gabi Huiber's blog.
> I'm in total agreement. But I want my program to be able to handle the
> use of delayed macro expansion if it's opted for.
>
> There's a question of whether I should even worry about a user
> attempting delayed macro expansion when clearly they shouldn't.
> StataCorp doesn't seem to care. For example:
> sysuse auto
> local nvals example
> levelsof foreign, local(`nvals')
> levelsof foreign, local(\`nvals')
>
> The second -levelsof-, where I use delayed macro expansion, stores the
> levels in the local `2', not `example' as expected. To prevent this
> possibility, you could add to levelsof.ado after -syntax-:
>
> local syntaxerr 0
> capture {
>   local temp "`local'"
> }
> mata: if (st_local("temp") != st_local("local")) st_local("syntaxerr", "1");;
> if `syntaxerr' {
>        di as err "option local(): delayed macro expansions not allowed"
>        ex 198
> }
>
> Is it worth the work? Probably not.
>
> Best,
> Matt
> On Sun, Jan 1, 2012 at 8:40 PM, Nick Cox <njcoxstata@gmail.com> wrote:
>> Sorry, but you have lost me.
>>
>> Local macros are Stata entities. Reading them into Mata to compare
>> them and writing back results to Stata looks unnecessarily roundabout.
>> I haven't felt a need for that hitherto.
>>
>> I can't see the logic of your first block of code. Local macro -temp-
>> is defined as a copy of local macro -str-. This can't fail as it is
>> legal whether -str- is empty or not, so I can't see the point of
>> -capture-. I don't see why you think that -capture- suppresses macro
>> expansion.
>>
>> As the two macros are now identical, there is no point to testing
>> whether they are not.
>>
>> I have a prejudice that delaying macro expansion is almost always
>> unnecessary, developed at length on Gabi Huiber's blog.
>>
>> http://enoriver.net/index.php/2011/02/10/delayed-macro-substitution/#comments
>>
>> The "almost always" is because I don't want to appear dogmatic, but I
>> can't recall a convincing example. áI have seen several very
>> unconvincing examples, however.
>>
>> Nick
>>
>> On Sun, Jan 1, 2012 at 11:29 PM, Matthew White
>> <mwhite@poverty-action.org> wrote:
>>> Hi Nick,
>>>
>>> Thanks for your response; that's a good idea. An empty string actually
>>> is acceptable, but I realized that I probably just don't want to allow
>>> the user to pass a macro expansion to the program. Of course, I want
>>> the user to be able to use macros, but I won't allow delayed macro
>>> expansions (e.g., using -\-). Supposing the string I'm parsing is
>>> stored in local `str', my code is:
>>>
>>> capture {
>>> á álocal temp "`str'"
>>> }
>>> mata: if (st_local("temp") != st_local("str")) st_local("syntaxerr", "1");;
>>> if `syntaxerr' {
>>> * error and exit
>>> }
>>>
>>> The -capture- block is to suppress the macro expansion error message;
>>> -capture- by itself doesn't seem to do this.
>>>
>>> Before I got to this point, I tried writing a Mata function that
>>> searches for embedded macro expansions in a string and tests them in
>>> Stata. If the expansion errors, the function errors. Unlike the
>>> expansion error, the function error can be picked up by -capture-. I
>>> haven't done much testing of the function, but here it is with an
>>> example in case there's interest:
>>>
>>> mata:
>>> void function checkstring(string scalar str)
>>> {
>>> á á á áreal scalar á match
>>> á á á ástring scalar expansion
>>>
>>> á á á ádo {
>>> á á á á á á á ámatch = regexm(str, "(`" + `"[^'"][^']*')"')
>>> á á á á á á á áif (match) {
>>> á á á á á á á á á á á áprintf("{txt}Evaluating: {res}%s\n", regexs(0))
>>> á á á á á á á á á á á áexpansion = strrtrim(substr(regexs(0), 2, strlen(regexs(0)) - 2))
>>> á á á á á á á á á á á áif (substr(expansion, 1, 1) == "=" | substr(expansion, 1, 1) == ":") {
>>> á á á á á á á á á á á á á á á ástata("local test " + expansion)
>>> á á á á á á á á á á á á}
>>> á á á á á á á á á á á áelse if (substr(expansion, 1, 2) == "++") {
>>> á á á á á á á á á á á á á á á ástata("local ++" + substr(expansion, 3, .))
>>> á á á á á á á á á á á á á á á ástata("local --" + substr(expansion, 3, .))
>>> á á á á á á á á á á á á}
>>> á á á á á á á á á á á áelse if (substr(expansion, -2, 2) == "++") {
>>> á á á á á á á á á á á á á á á ástata("local ++" + substr(expansion, 1, strlen(expansion) - 2))
>>> á á á á á á á á á á á á á á á ástata("local --" + substr(expansion, 1, strlen(expansion) - 2))
>>> á á á á á á á á á á á á}
>>> á á á á á á á á á á á áelse if (substr(expansion, 1, 2) == "--") {
>>> á á á á á á á á á á á á á á á ástata("local --" + substr(expansion, 3, .))
>>> á á á á á á á á á á á á á á á ástata("local ++" + substr(expansion, 3, .))
>>> á á á á á á á á á á á á}
>>> á á á á á á á á á á á áelse if (substr(strrtrim(expansion), -2, 2) == "--") {
>>> á á á á á á á á á á á á á á á ástata("local ++" + substr(expansion, 1, strlen(expansion) - 2))
>>> á á á á á á á á á á á á á á á ástata("local --" + substr(expansion, 1, strlen(expansion) - 2))
>>> á á á á á á á á á á á á}
>>>
>>> á á á á á á á á á á á ástr = regexr(str, "`" + `"[^'"][^']*'"', "")
>>> á á á á á á á á}
>>> á á á á} while(match)
>>> }
>>> end
>>>
>>> capture noi mata: checkstring("\`='Hello world")
>>> di _rc
>>>
>>> Best,
>>> Matt
>>>
>>> On Sun, Jan 1, 2012 at 2:26 PM, Nick Cox <njcoxstata@gmail.com> wrote:
>>>> You could try testing whether the expression evaluates to an empty
>>>> string. The usefulness of that approach depends on whether an empty
>>>> string is acceptable on other grounds.
>>>>
>>>> Nick
>>>>
>>>> On Sun, Jan 1, 2012 at 7:04 PM, Matthew White <mwhite@poverty-action.org> wrote:
>>>>
>>>>> Using Stata 11.2 SE, I'm writing a program that requires me to parse a
>>>>> string passed to the program. I want the program to exit if the string
>>>>> contains a macro expansion that results in an error. Currently, Stata
>>>>> displays an error about the macro expansion without exiting, and then
>>>>> continues to parse the string and run the program. Generally, I want
>>>>> to know how I can detect whether a command results in a macro
>>>>> expansion error. Here's an example of what I mean:
>>>>>
>>>>> . display "`='Hello world"
>>>>> invalid syntax
>>>>> Hello world
>>>>>
>>>>> Here, the macro expansion `=' results in an invalid syntax error, but
>>>>> -display- is still executed (after `=' evaluates to ""), and there's
>>>>> no return code (r(198) is not displayed). -capture- doesn't help:
>>>>>
>>>>> . capture display "`='Hello world"
>>>>> invalid syntax
>>>>>
>>>>> . display _rc
>>>>> 0
>>>>>
>>>>> Essentially what I'd like is something like -capture- that I can use
>>>>> to determine whether a command results in a macro expansion error. Any
>>>>> ideas?
>>>>>

*
*   For searches and help try:
*   http://www.stata.com/help.cgi?search
*   http://www.stata.com/support/statalist/faq
*   http://www.ats.ucla.edu/stat/stata/


© Copyright 1996–2018 StataCorp LLC   |   Terms of use   |   Privacy   |   Contact us   |   Site index