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   Matthew White <[email protected]>
To   [email protected]
Subject   Re: st: Detecting a macro expansion error
Date   Sun, 1 Jan 2012 22:22:31 -0500

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 <[email protected]> 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
> <[email protected]> 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 <[email protected]> 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 <[email protected]> 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/
>>
>>
>>
>> --
>> Matthew White
>> Data Coordinator
>> Innovations for Poverty Action
>> 101 Whitney Avenue, New Haven, CT 06510 USA
>> +1 434-305-9861
>> www.poverty-action.org
>>
>> *
>> *   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/
>
> *
> *   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/



-- 
Matthew White
Data Coordinator
Innovations for Poverty Action
101 Whitney Avenue, New Haven, CT 06510 USA
+1 434-305-9861
www.poverty-action.org

*
*   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