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!
>>>>
>>>  ​
>

Reply via email to