One of the big difficulties for Crystal users, IMO, is that macro error messages are often incomprehensible. I recently came up with a means of giving users a bit more clue, which is shown in the error report from --error-trace and does not add space in the compiled code. Here is some sample macro code to demonstrate what I’m doing:
macro delegate2(name, to, file = __FILE__, line = __LINE__)
# This method was generated through an invocation of
# `{{@type.name}}.delegate2 {{name}}, to: {{to}}`
# at {{file.id}}:{{line.id}}.
When I test the code with a deliberately-injected error, I get this output from crystal build --error-trace
. Every ASTNode, and thus every macro argument, includes ASTNode#filename
and ASTNode#line_number
, you don’t have to pass FILE and LINE.
There was a problem expanding macro 'delegate2'
Called macro defined in delegate.cr:2:3
2 | macro delegate2(name, to, file = __FILE__, line = __LINE__)
Which expanded to:
> 1 |
... (blank lines)
> 31 |
> 32 | # This method was generated through an invocation of
> 33 | # `A.delegate2 inspect, to: @a`
> 34 | # at /home/bruce/Crystal/delegate/src/delegate.cr:46.
> 35 | # The target method is at
> 36 | # /usr/share/crystal/src/reference.cr:71
> 37 | def inspect(io : IO) : Nil
> 38 | @a.inspect(io)
> 39 | @a.foobar
> 40 | end
> 41 |
... (blank lines)
> 74 |
> 75 | # This method was generated through an invocation of
> 76 | # `A.delegate2 inspect, to: @a`
> 77 | # at /home/bruce/Crystal/delegate/src/delegate.cr:46.
> 78 | # The target method is at
> 79 | # /usr/share/crystal/src/object.cr:155
> 80 | def inspect(io : IO) : Nil
> 81 | @a.inspect(io)
> 82 | @a.foobar
> 83 | end
> 84 |
... (blank lines)
> 93 |
> 94 | # This method was generated through an invocation of
> 95 | # `A.delegate2 inspect, to: @a`
> 96 | # at /home/bruce/Crystal/delegate/src/delegate.cr:46.
> 97 | # The target method is at
> 98 | # /usr/share/crystal/src/object.cr:143
> 99 | def inspect() : String
> 100 | @a.inspect()
> 101 | @a.foobar
> 102 | end
The progam containing this is at https://github.com/BrucePerens/delegate
Now, while comments work, especially with error trace on, we could improve on this:
- Assign an annotation that will be output when there is an error in a macro, even without --error-trace. Macro developers could put information about the macro arguments in it.
- Just print the filename and line number of all macro arguments in macro error messages.