Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluate yield expressions in macros #2924

Closed
asterite opened this issue Jun 28, 2016 · 5 comments
Closed

Evaluate yield expressions in macros #2924

asterite opened this issue Jun 28, 2016 · 5 comments
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler

Comments

@asterite
Copy link
Member

asterite commented Jun 28, 2016

This currently doesn't work:

macro a(b)
  {{yield b}}
end

a("foo") do |c|
  puts {{c}}
end

The error is:

Error in bar.cr:5: expanding macro

a("foo") do |c|
^

in bar.cr:2: undefined local variable or method 'b' (did you mean 'p'?)

  {{yield b}}
          ^

One would expect b to be evaluated to "foo", and have that be yielded to the block.

The yield expression is currently not evaluated because it's used here:

{{yield LibCrystalMain.__crystal_main(argc, argv)}}

because we want to embed LibCrystalMain.__crystal_main(argc, argv) inside the resulting program.

The correct way to do this last thing would be to do:

{{yield "LibCrystalMain.__crystal_main(argc, argv)".id}}

that is, pass a MacroID to the block. And then yield should evaluate its expressions as expected.

@asterite asterite added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler labels Jun 28, 2016
@asterite asterite changed the title Correctly define the semantics of yielding something in macros Evaluate yield expressions in macros Jun 28, 2016
@jhass
Copy link
Member

jhass commented Jun 28, 2016

One minor consistency issue left here is that it's a bit unobvious on the call side, that do |c| defines a macro parameter and not a local. However I doubt we can solve this without adding fundamentally different syntax, like a("foo") provide |c| or whatever, which is just as much effort to learn than the inconsistency.

@asterite
Copy link
Member Author

But since a is a macro call that's later replaced by the macro result... what would the block mean other than variables passed by the macro to it?

@jhass
Copy link
Member

jhass commented Jun 28, 2016

Nothing, the argument is that the call side looks just like a regular method call with a block, so the semantics within the block changing might surprise one.

@asterite
Copy link
Member Author

To be honest, I implemented that "feature" of yielding parameters into the macro call very quickly and dirty(-ly?) and I can see it's half-backed, as you for example can't do anything with those yielded expressions other than paste them with {{...}}, so it's good to discuss this now :-)

About your last comment, other languages use a different syntax for macro calls, for example in Rust names have a bang at the end. Maybe that's a problem in Crystal because there's no distinction between regular calls and macro calls... this makes things more similar to Ruby, and maybe it's better this way because the user doesn't have to worry about this.

The problem with yielding things into a macro call is that one has to know it's a macro, and use the macro language inside it, for example paste the expression with {{...}}. We could maybe remove this feature entirely, or disable it for now, though we'd have to find another way to do redefine_main.

@jhass
Copy link
Member

jhass commented Jun 28, 2016

I just wanted to bring it up in case I was missing an obvious neat solution to it. I don't think it's much of an actual issue, at worst it adds another edit/compile cycle into the workflow because the compiler tells you this was actually a macro call, implicitly. We already have that issue with for example the record macro accepting method definition in its block, which a regular method call never would.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler
Projects
None yet
Development

No branches or pull requests

3 participants