Open LoadingBG opened 2 years ago
The problem is likely with self yield
for which there's no defined implementation. That should probably produce a compiler error.
To be clear: it's the macro expression with self yield
.
You don't really need that, though. Just use {{ yield }}
. Macro yield
needs no with self
because the block's code is statically embedded into the parent context and everything should work then as expected.
Removing it gives the exact same error.
Than it's something else apparently.
It probably create_playground
which is a method and inside that method you re-open a class to define methods in that class. That doesn't work. Maybe the error message is weird because it happens from a macro expansion. Perhaps it's some other error in the macro evaluation.
Reduced:
struct Int32
macro bar
class Foo
end
end
end
def foo
with 1 yield
end
foo do
bar do
end
end
It's trying to declare a class inside with ... yield
. That should produce an error ("can't dynamically declare class") but that's not the case.
I was making a simple Logo language DSL. Logo has the command
TO
which defines a new instruction with the following syntax:I created the following macro to try to replicate the syntax as close as possible:
and used it like so:
where
repeat
,forward
andright
are methods defined in the class.The macro gives the following error:
Using
{% debug %}
at the end of the macro prints this:Versions:
crystal -v
:OS: Ubuntu 20.04 running in WSL
Full code if needed
```cr module Turtle class Turtle @x : Int32 @y : Int32 @initialX : Int32 @initialY : Int32 @angle : Int32 def initialize(@initialX : Int32, @initialY : Int32) : Nil @x = @initialX @y = @initialY @angle = 0 end private def to_radians(degrees : Int32) : Float64 degrees * Math.acos(-1) / 180 end def forward(steps : Int32) : Nil radians = to_radians(@angle) @x += (steps * Math.sin(radians)).to_i @y -= (steps * Math.cos(radians)).to_i end def backward(steps : Int32) : Nil forward(-steps) end def right(angle : Int32) : Nil @angle += angle end def left(angle : Int32) : Nil right(-angle) end def repeat(times : Int32, &instructions : Int32 ->) : Nil 1.upto(times) do |repcount| with self yield repcount end end macro to(name) class Turtle def {{name.id}} {{with self yield}} end end {% debug %} end def inspect(io : IO) : Nil io << "Turtle(" << @x << ", " << @y << ", " << @angle << ")" end def to_s : String builder = String::Builder.new inspect(builder) builder.to_s end end end def create_playground : Nil turtle = Turtle::Turtle.new(100, 100) with turtle yield end create_playground do to square do repeat 4 do forward 100 right 90 end end square puts to_s end ```