The Crystal Programming Language Forum

Feature request: macro to pass code to command

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.

1 Like

Awesome, thanks!