From cf0bd6e25bbd700911caabd4492e19d5278b4efb Mon Sep 17 00:00:00 2001 From: George Dietrich Date: Fri, 22 Dec 2023 09:17:34 -0500 Subject: [PATCH] Document new `@caller` macro ivar (#724) --- docs/syntax_and_semantics/macros/README.md | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/syntax_and_semantics/macros/README.md b/docs/syntax_and_semantics/macros/README.md index 82820cfca..c7569d9d4 100644 --- a/docs/syntax_and_semantics/macros/README.md +++ b/docs/syntax_and_semantics/macros/README.md @@ -342,6 +342,29 @@ end Foo.boo(0, 1) ``` +## Call Information + +When a macro is called, you can access the macro call stack with a special instance variable: `@caller`. +This variable returns an `ArrayLiteral` of [`Call`](https://crystal-lang.org/api/Crystal/Macros/Call.html) nodes with the first element in the array being the most recent. +Outside of a macro or if the macro has no caller (e.g. a [hook](./hooks.md)) the value is a [`NilLiteral`](https://crystal-lang.org/api/Crystal/Macros/NilLiteral.html). + +NOTE: As of now, the returned array will always only have a single element. + +Example: + +```crystal +macro foo + {{ @caller.first.line_number }} +end + +def bar + {{ @caller }} +end + +foo # => 9 +bar # => nil +``` + ## Constants Macros can access constants. For example: @@ -475,6 +498,31 @@ a The expression above will result in no output. +### Merging Expansion and Call Comments + +The [`@caller`](#call-information) can be combined with the [`#doc_comment`](https://crystal-lang.org/api/Crystal/Macros/ASTNode.html#doc_comment%3AMacroId-instance-method) method in order to allow merging documentation comments on a node generated by a macro, and the comments on the macro call itself. For example: + +```crystal +macro gen_method(name) + # {{ @caller.first.doc_comment }} + # + # Comment added via macro expansion. + def {{name.id}} + end +end + +# Comment on macro call. +gen_method foo +``` + +When generated, the docs for the `#foo` method would be like: + +```text +Comment on macro call. + +Comment added via macro expansion. +``` + ## Pitfalls When writing macros (especially outside of a macro definition) it is important to remember that the generated code from the macro must be valid Crystal code by itself even before it is merged into the main program's code. This means, for example, a macro cannot generate a one or more `when` expressions of a `case` statement unless `case` was a part of the generated code.