I know there is a macro method to call out to a system command
https://crystal-lang.org/api/0.32.1/Crystal/Macros.html#system(command):MacroId-instance-method
It would be interesting to me, at least from an curiosity perspective, to be able to pass an AST or a “string block of code” to that command so it could return something and effectively rewrite existing crystal code. Just a thought/idea. Sorry I know I’ve requested it before LOL.
Cheers!
You can already do that. Pass a string representation of the ast to the macro, let the macro parse it, transform it, return it, and then you paste the result into the program.
1 Like
Nice. It’s possible to pass the string as a parameter to the system command? Examples would be wonderful, thanks, I’m not experienced with macros…
Sure!
# foo.cr
macro foo(ast)
{{ run "./bar", ast }}
{% debug %}
end
foo def add(x, y)
x + y
end
p add(2, 3)
# bar.cr
require "compiler/crystal/syntax"
include Crystal
code = ARGV[0]
nodes = Parser.parse(code)
a_def = nodes.as(Def)
a_def.body = Call.new(Var.new("x"), "*", Var.new("y"))
puts a_def.to_s
So we pass a def
to the macro, we get it on bar
(as code), we parse it and then modify the body to do a multiplication instead of an addition.
If you want to modify code in a more generic way you probably want to use a Crystal::Transformer
.
I don’t know what use cases this has, but it’s possible.
It’s a bit slow to compile the first time but subsequent times should be faster.
4 Likes