Awesome, thanks for the suggestions. I ended up independently implementing your second solution, which I think is the more elegant way to do it. But it's good to know about the first approach as well.
For anyone who is interested, here's the code I ended up with: # general case, just return value expand_names(value) = value # if it's a symbol, check that it matches, and if so, convert it function expand_names(sym::Symbol) m = match(r"_(\d+)", string(sym)) if m !== nothing return :(children[parseint($(m.captures[1]))]) end return sym end # if it's an expression, recursively go through tree and # transform all symbols that match '_i' function expand_names(expr::Expr) new_args = [expand_names(arg) for arg in expr.args] return Expr(expr.head, new_args...) end Then, you can can run expand_names on any expression/symbol passed via the braces. On Friday, March 6, 2015 at 10:58:43 PM UTC-5, Jameson wrote: > > oh, that’s reasonably easy then: > > macro testfn(expr) > children = esc(:children) > syms = [:($(symbol(string("_", i))) = $children[$i]) for i = 1:10] > return Expr(:let, Expr(:block, esc(expr)), :(children=children), syms..) > end > > which will expand to: > > let children=children, _1 = children[1], _2 = children[2], ... > $expr > end > > (I added the first children=children line, so that the user could > theoretically assign to a variable named children, without leaking it to > the enclosing environment. it's not strictly necessary). > > ----- > > alternatively, you could recurse through their expr code and replace all > variables of the form `_(\d+)` with :(children[\1]) > > ----- > > > On Fri, Mar 6, 2015 at 9:30 PM Abe Schneider abe.schnei...@gmail.com > <http://mailto:abe.schnei...@gmail.com> wrote: > > Hmmm, good to know. Thank you. >> >> The rationale for doing so is to provide a shortcut for the elements of >> a variable `children`. Specifically, for a grammar, I might have a rule >> like: >> >> ``` >> @grammar foo begin >> number = r"[0-9]+" { parseint(children[1]) } >> end >> ``` >> >> What I would like to have instead, to make it more succint is: >> >> ``` >> @grammar foo begin >> number = r"[0-9]+" { parseint(_1) } >> end >> ``` >> >> Originally, just to get things working, I used an `eval`, which while >> worked, also made the assignment global, which was less than ideal. >> >> >> I'd be curious if anyone has a suggestion on other methods to accomplish >> this, or if this is outside the scope of what's possible to do with Julia. >> >> >> >> On Friday, March 6, 2015 at 5:10:07 PM UTC-5, Jameson wrote: >> >>> you can't do what you are proposing, by design. a macro cannot do >>> anything that you cannot express directly, it simply allows you to express >>> it more succinctly by templating the redundant parts. >>> >>> if you want a "set" or "numbered list", use a set or number list. >>> variables are bad at that sort of task. whereas an Array is very good at it. >>> >>> On Fri, Mar 6, 2015 at 8:05 AM Abe Schneider <abe.sc...@gmail.com> >>> wrote: >>> >>>> I'm trying to create a set of variables (_1, _2, ...) from items within >>>> a list in a macro. I have a (much) condensed version of the code: >>>> >>>> macro testfn() >>>> quote >>>> i = 1 >>>> value = [1, 2, 3] >>>> $(Expr(:(=), Expr(:symbol, Expr(:string, "_", :i)), :value)) >>>> println(_1) >>>> end >>>> end >>>> >>>> >>>> which gives me: >>>> >>>> ERROR: syntax: invalid assignment location >>>> >>>> >>>> Any ideas on what might be wrong or the proper way to do this? I would >>>> like to keep this in the quotes, as in the actual version there's a lot >>>> more code surrounding the assignment. >>>> >>>> I can get things to work with an eval, but I rather avoid the eval, and >>>> it appears to create a non-local variable. >>>> >>>> >>>> Thanks! >>>> >>> >