Functions defined with the `macro` keyword are not actual functions, but they are used as syntax replacements.
It implies the following:
* macros must return `void`
* cannot be `inline`, `noinline` or `extern`
* can be `asm` - in this case, they should **not** end with a return instruction
* do not have an address
* their invocations cannot be used as expressions
* in case of `asm` macros, the parameters must be defined as either `const` (compile-time constants) or `ref` (variables)
* in case of non-`asm` macros, the parameters must be variables
* macros do not have their own scope (they reuse the scope from their invocations) – exceptions: the parameters and the local labels defined in assembly
* control-flow statements (`break`, `continue`, `return`, `goto`, `label`) are run as if places in the caller function
When invoking a macro, you need to pass variables as arguments to parameters annotated with `ref` and constants as arguments annotated with `const`.
You can invoke a macro from assembly, by preceding the invocation with `+`