Sadly it looks like this doesn't entirely solve the problem. The issue is 
that while it does indeed insert the function into the Expr tree, the 
namespace for the variables is for the module that the macro is defined in, 
and not the user's file (the standard issue with eval'ing).

For example, suppose I define a custom functions `foo` and `bar` in my file 
and define a rule like:

value = integer { foo(_1) } | float { bar(_1) }

the execution will fail since `foo` and `bar` are not defined.


On Thursday, March 19, 2015 at 9:59:19 AM UTC-4, Jameson wrote:
>
> yes and no. the definition of your insert_expr function below is:
>
> insert_expr(fn_expr) = @eval (rule, first, last, children) -> $fn_expr
>
> so it’s not hard to define. but you could also just have 
> parse_action_definition return the necessary function in the first place.
> @eval is relatively expensive, since it will analyze the expression. this 
> is good, under the assumption that the resulting function will be reused 
> many times. but really bad if the user then tries to write a giant for loop 
> that repeated calls eval on the same thing. whereas wrapping the same 
> expression in an function, evaluating that once, then calling the function 
> repeatedly in the for loop lets the compiler optimize the loop much better. 
> eval is intentionally somewhat restricted in its abilities (such as not 
> being able to see local scope), specifically to make such abuses harder / 
> more obvious.
>
> On Thu, Mar 19, 2015 at 7:31 AM Abe Schneider abe.schnei...@gmail.com 
> <http://mailto:abe.schnei...@gmail.com> wrote: 
>
> Thank you Jameson, that makes a lot of sense. Generally I try to organize 
> my code to build up a single Expr, but sometimes it makes for less than 
> ideal code.
>
> Out of curiosity, would it make sense for Julia to have an 'insert' 
> function to convert Expr's to ASTs? This would help alleviate the need for 
> macros in certain cases as well 'eval'. For example, in my case, if I had:
>
> fn_expr = parse_action_definition(rule)  # fn(rule, first, last, children)
> rule.action = insert_expr(fn_expr)
>
> would cause `rule.action` be set to the actual function, rather than the 
> Expr. If you tried to use `eval`, not only is it frowned on, but it would 
> also fail because of it's global scope.
>
> While ultimately you can by, as you suggest, with building up the Exprs, I 
> think something like this would allow for easier to read/maintain code.
>
>
>
> On Thursday, March 19, 2015 at 12:43:29 AM UTC-4, Jameson wrote:
>
> writing a code snippet like
>
> val = :(parsefloat("3.1459"))
> @test2(val)
>
> is perhaps a great way to confuse yourself, although it is a common 
> mistake.
>
> the problem is that it makes it seem like the two arguments execute in 
> sequence, whereas the macro expansion pass actually runs prior to the code 
> execution. it should, therefore, be viewed in complete isolation from the 
> runtime expressions. in pseudo-code, that might look something like:
>
> fullexpression = macroexpand(:(@test2(val)))
> ///
> val = :(parsefloat("3.1459"))
> $fullexpression
>
> in summary, macros are functions whose arguments are syntax, not values. 
> when a macro is executed, val does not get passed as reference to a value 
> stored in a variable, it is the expression tree that describes that 
> variable. that is the fundamental distinction between a function and a 
> macro.
>
> but, it doesn't sound like you need a macro. macros that call other macros 
> can get really confusing really quickly. but a normal function will perhaps 
> do exactly what you wanted anyways? it's perfectly valid for you to write a 
> function that takes `val` in as an argument and returns some new expression 
> (which you can then combine with other expressions before returning the 
> whole thing from the main macro)
>
>
> On Wed, Mar 18, 2015 at 9:51 AM Abe Schneider abe.schnei...@gmail.com 
> <http://mailto:abe.schnei...@gmail.com> wrote:
>
> Unfortunately my solution only works if you pass in an expression 
> directly. If you try something like this:
>
> val = :(parsefloat("3.1459"))
> @test2(val)
>
> It will fail, since `val` is a symbol. Any other ideas?
>
>
> The reason I'm trying to solve the problem in the first place is that I 
> have semantic actions attached to rules formed in a grammar. The actions 
> take the form of expression, which I want to wrap up in a function like:
>
> (rule,first, last,children) -> $ex
>
> where `$ex` is my found expression. If I do this in my main macro, 
> everything work correctly. However, the logic gets more complicated, 
> because I want to allow semantic actions to be tied to any subrule, which 
> means it has to be handled in the definition parsing functions. That should 
> be fine, but I try to create a function that wraps my function, I get into 
> this issue. I can't just insert the expression into the AST like I did 
> before.in the main macro.
>
>
> On Wednesday, March 18, 2015 at 9:30:32 AM UTC-4, Abe Schneider wrote:
>
> After some thought, I realized that the easiest way to unquote is to reach 
> inside the Expr and pull out what is needed. If I do a dump of `ex` I get:
>
> Expr 
>   head: Symbol quote
>   args: Array(Any,(1,))
>     1: Expr 
>       head: Symbol call
>       args: Array(Any,(2,))
>         1: Symbol parsefloat
>         2: ASCIIString "3.1459"
>       typ: Any
>
>
> So I can rewrite the macro as:
>
> macro test2(ex)
>   ex.args[1]
> end
>
> which appears to work:
>
> @test2(:(parsefloat("3.1459")))
>
> # 3.1459
>
>
>
>
>
> On Wednesday, March 18, 2015 at 8:08:35 AM UTC-4, Abe Schneider wrote:
>
> If I do something simple like:
>
> macro test()
>  :(parsefloat("3.1459"))
> end
>
> @test() 
>
> # 3.1459
>
> everything works as expected. However, if I try this instead:
>
> macro test2(ex)
>  ex
> end
>
> @test2(:(parsefloat("3.1459")))
>
> # :(parsefloat("3.1459"))
>
>
> Not what I expected, but it makes sense what's happening:
>
> macroexpand(:(@test(:(parsefloat("3.1459")))))
>
> # :($(Expr(:copyast, :(:(parsefloat("3.1459"))))))
>
> So, anything I pass to the macro is automatically quoted. Obviously if I 
> just do:
>
> @test2(parsefloat("3.1459"))
>
> it will work. However, the use-case I'm trying to deal with is that I have 
> an Expr that I would like inserted into the AST. Besides being frowned on, 
> I can't eval, due to not wanting things to be evaluated in global space.
>
> Is there some way I can unquote the expression in the macro for test2?
>
> ​
>
> ​
> ​
> ​
>
> ​
> ...

Reply via email to