diff --git a/docs/abi/inlining.md b/docs/abi/inlining.md index e7af97df..637d7801 100644 --- a/docs/abi/inlining.md +++ b/docs/abi/inlining.md @@ -4,7 +4,74 @@ ## Macros -`macro` keyword +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 `+` + +Examples: + + macro void inc_x() { + x += 1 + } + byte add_two_1(byte x) { + inc_x() + inc_x() + return x + } + + macro void inc(byte b) { + b += 1 + } + byte add_two_2(byte x) { + inc(x) + inc(x) + return x + } + + macro void add(byte b, byte v) { + b += v + } + macro void retu(byte result) { + return result + } + byte add_two_3(byte x) { + add(x, 2) + retu(x) + } + + macro asm byte add_asm(byte ref b, byte const v) { + LDA b + CLC + ADC #v + // no RTS! + } + byte add_two_4(byte x) { + add_asm(x, 2) + return x + } + ## Automatic inlining