I still haven't been able to get the code to work with using quotes.
However, with some experimentation I was able to write things out directly
with Exprs. A condensed version of the code is:
macro grammar(grammar_name::Symbol, ex::Expr)
code = {}
push!(code, :(rules = Dict()))
for definition in ex.args[2:2:end]
name = Expr(:call, :string, Expr(:quote, definition.args[1]))
ex = Expr(:quote, definition.args[2])
action = Expr(:escape, definition.args[1].args[2])
# rules[name] = parseDefinition(name, ex, nothing)
push!(code, Expr(:(=), Expr(:ref, :rules, name),
Expr(:call, :parseDefinition, name, ex, action)))
end
# grammar_name = Grammar(rules)
push!(code, :($(esc(grammar_name)) = Grammar(rules)))
return Expr(:block, code...)
end
The tricky part being the definition of `action`. It can't be evaluated in
the macro itself, as it would be in the wrong namespace, and thus had to be
escaped. In a separate thread Tim Holy provided a method to get the
expression passed to the `parseDefinition` method, but I couldn't get it to
work with everything else.
I actually think keeping everything as `Expr`s is easier to understand,
though I'm still curious how to properly express this in quote form.
On Thursday, August 7, 2014 1:51:30 PM UTC-4, Jameson wrote:
>
> A function which has access to the namespace in which it was defined is
> also known in Julia as a closure, or simply function. All functions are
> first-class objects, which don't need eval or macros. Eval and macros are
> really bad at pretending to be functions.
>
> Without a bit more example code, it is hard to understand what problem you
> are trying to solve. Macros are for reducing typing (syntax transforms),
> not magic (altering the environment), which is why they generally don't
> have access to the environment.
>
> On Friday, August 1, 2014, Abe Schneider <[email protected]
> <javascript:>> wrote:
>
>> I tried a second approach where instead of keeping a function around I
>> keep just the symbol. I have a `transform` function that applies the
>> function to the resulting values. However, this only moves the problem to a
>> new place. In my `transform` method I have:
>>
>> eval(Expr(:call, action, values))
>>
>>
>> where `action` is the symbol that I am now carrying around. The `eval`
>> still works in the module's namespace, so I get the same error.
>>
>> If Julia had a way to access the namespace from the calling function,
>> this could be made to work. Or for that matter, if I could get the calling
>> namespace from the macro, I could then just get the macro that way.
>>
>> I'm guessing Julia doesn't currently have this functionality, but would
>> it be something possible to add?
>>
>> On Friday, August 1, 2014 12:22:46 PM UTC-4, Abe Schneider wrote:
>>>
>>> I think the problem is that I'm not accessing it directly through the
>>> macro parameters. The call:
>>>
>>> @grammar foo begin ... end
>>>
>>> passes just the single expression block to `foo`. Thus, I'm getting the
>>> function from the resulting Expr tree. Even if I quote it, it still ends up
>>> as an expression that contains a symbol that must be evaluated (unless I'm
>>> missing something...)
>>>
>>>
>>> On Friday, August 1, 2014 11:42:52 AM UTC-4, Simon Kornblith wrote:
>>>>
>>>> That looks like the output of :(esc(fn)), but you don't want to quote
>>>> that, you want to evaluate it when generating the code, i.e. use
>>>> $(esc(fn)) wherever you were previously using $fn
>>>>
>>>> On Friday, August 1, 2014 11:38:44 AM UTC-4, Abe Schneider wrote:
>>>>>
>>>>> That's correct, I'm generating code that keeps a pointer to that
>>>>> function to call later on.
>>>>>
>>>>> If I do that, I have the type `esc(fn)` in the macro (this is what I
>>>>> get when printing it out), and taking a dump of that argument gives:
>>>>>
>>>>> Expr
>>>>> head: Symbol call
>>>>> args: Array(Any,(2,))
>>>>> 1: Symbol esc
>>>>> 2: Symbol fn
>>>>> typ: Any
>>>>>
>>>>>
>>>>> Does that mean instead of carrying around a function I will need to
>>>>> carry around the Expr?
>>>>>
>>>>> Thanks!
>>>>>
>>>>> On Friday, August 1, 2014 11:17:50 AM UTC-4, Simon Kornblith wrote:
>>>>>>
>>>>>> Assuming you're generating code that calls fn, as opposed to trying
>>>>>> to call it when generating code in the macro (usually a bad idea), you
>>>>>> should use esc(fn) in place of fn
>>>>>>
>>>>>> On Friday, August 1, 2014 10:50:15 AM UTC-4, Abe Schneider wrote:
>>>>>>>
>>>>>>> I've come across a problem where I have macro to define a grammar
>>>>>>> (similar to how PEGParser currently works):
>>>>>>>
>>>>>>> @grammar foo begin
>>>>>>> rule[fn] = "some" + ("rule" | "test")
>>>>>>> end
>>>>>>>
>>>>>>> where the `[fn]` next to the rule defines a function to call on the
>>>>>>> results (in this case it's an expansion). The issue is that parsing the
>>>>>>> Expr tree, `fn` is given as a Symbol (which makes sense).
>>>>>>>
>>>>>>> However, if I try to turn `fn` into a function I run into the
>>>>>>> namespace issue I've had previously. If `fn` is defined in my module,
>>>>>>> it
>>>>>>> works without problem. If it's defined in the code that imports the
>>>>>>> module,
>>>>>>> it will not work because that function doesn't exist in the namespace
>>>>>>> of
>>>>>>> the module.
>>>>>>>
>>>>>>> I'm guessing there isn't an easy solution to fix this problem, but I
>>>>>>> thought I'd check to see if someone had an idea.
>>>>>>>
>>>>>>> Thanks!
>>>>>>>
>>>>>>>