Skip to content

Commit

Permalink
Document new @caller macro ivar (#724)
Browse files Browse the repository at this point in the history
  • Loading branch information
Blacksmoke16 authored Dec 22, 2023
1 parent e7aa99a commit cf0bd6e
Showing 1 changed file with 48 additions and 0 deletions.
48 changes: 48 additions & 0 deletions docs/syntax_and_semantics/macros/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit cf0bd6e

Please sign in to comment.