Notice: On April 23, 2014, Statalist moved from an email list to a forum, based at statalist.org.
From | Matthew White <mwhite@poverty-action.org> |
To | statalist@hsphsun2.harvard.edu |
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 <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/ >> >> >> >> -- >> 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/