LEVIATHAN v962456e · 962456eee1

Metaprogramming

Body-generating rules — generates and replace

A generates body of rule replaces a method's body outright and discards the original, for stubs whose body is machine-filled.

since 0.1.0-alpha.1linuxwindowswasm

Description

generates body of <bind> is the sibling of rewrites. It overwrites the target's body wholesale and discards the original, for a rule whose point is that there is no original to compose with: a binding stub, a foreign-function shim, a codec, any "declare the signature, machine-fill the body" generator. The signature and the data that drives generation, such as an @Extern-shaped attribute, sit on the hand-written declaration, and only the body is generated.

rule name generates body of m {
    match @Attr(a) on method m
    replace `<template>`
}

Here every @Extern method forwards to a host object through its operation name. The placeholder body => "" is thrown away and never runs:

Generating a body

namespace Bindgen {
    attribute Extern { string op; }
    rule bindStr generates body of m {
        match @Extern(e) on method m
        replace `return host.call($e.op, $_args);`
    }
}
uses Bindgen;

class Host {
    string call(string op, string arg) => op + "(" + arg + ")";
}

class Widget {
    Host host = Host();

    @Extern("getAttribute")
    string attr(string name) => "";
}

console.writeln(Widget().attr("id"));
getAttribute(id)

$_args forwards the matched method's own parameters, so host.call($e.op, $_args) passes name through without writing the parameter list again.

Rules

  • The header is rule name generates body of m { match … replace <template> }. As with rewrites, the rule uses replace, not inject, and the matched bind must be a method or function.
  • $body is unavailable in a generates template. Naming it is a compile error that says the original body is discarded and suggests rewrites. This is the opt-in counterpart of the rewrites rule that a template must keep its $body exactly once: generates makes the drop explicit in the rule header.
  • $_args forwards the matched method's parameters verbatim. A hand-written family of overloaded helpers can then place each argument by its type, so a generates template needs no branching even when different call shapes need different handling.
  • A declaration whose body is missing, such as string attr(string name);, is accepted as the target, and the rule supplies the body. A placeholder body is equally fine.
  • Everything else about rewrites applies unchanged: the matched bind must be callable, two whole-body replacements on one body do not compose, reentrant works, and rewriters and generators run after all additive inject rules.

Examples

The method may be declared without any body at all:

A declaration with no body

namespace Bindgen {
    attribute Constant { int value; }
    rule constant generates body of m {
        match @Constant(c) on method m
        replace `return $c.value;`
    }
}
uses Bindgen;

class Limits {
    @Constant(64) int maxItems();
    @Constant(8) int maxDepth() => 0;
}

Limits l = Limits();
console.writeln(l.maxItems());
console.writeln(l.maxDepth());
64
8

Notes

  • A rule's trigger attribute should be your own. Attributes whose names begin with two underscores are reserved for the standard library's own rules, so a user attribute never collides with them.

See also