-
-
Notifications
You must be signed in to change notification settings - Fork 0
Typed Macros
A Pudu macro transforms parsed syntax. Its parameters declare the syntactic category accepted at each call site, and its call spelling remains visibly distinct from a function call.
macro twice(value: expr) = {
let held = value
held + held
}
fn main() -> Int {
twice!(3)
}
The expr annotation means the argument must parse as an expression. Calls use !, so reading
source does not require prior knowledge of which declarations are macros.
| Category | Accepts |
|---|---|
expr |
One parsed expression. |
ident |
One identifier. |
block |
One parsed block. |
Arity is exact. Arguments are parsed before substitution, preserving the grouping written by the caller. Pudu does not expose an untyped token stream or a repetition matcher in the current macro system.
Bindings introduced by an expansion are renamed for that expansion. In twice, the internal name
held cannot capture a caller binding with the same spelling, and a caller name cannot capture
it. The renaming follows lexical scope, including the success-only bindings of if let and the
body-only bindings of while let.
Hygiene applies to introduced bindings, not to the public names intentionally passed as ident
arguments. An identifier parameter is the explicit boundary for syntax whose name comes from the
call site.
Expansion precedes ordinary resolution and type checking. The expanded syntax must therefore be a valid program under the same rules as handwritten syntax. Expansion is bounded; recursive expansion that exhausts the bound is diagnosed at the macro call span.
The current syntax nodes retain the call span used for diagnostics. A full provenance chain that simultaneously exposes every definition and expansion site is not implemented.
Macros cannot read files, inspect environment variables, access the network, call arbitrary host code, or reach compiler internals. They are syntax transformers, not build scripts. This keeps a macro invocation reproducible from its source and arguments.
Use a function when ordinary values and types can express the operation. Functions compose with generic code, trait bounds, first-class function values, and normal tooling without expansion. Use a macro when syntax itself is the input—for example, when a block or identifier must be placed into a generated construct.
twice! is pedagogical, not an argument that arithmetic should normally be a macro. A generic or
ordinary function is the clearer abstraction when it can state the same contract.
- Modules And Imports
- Values, Bindings, And Blocks
- Types And Inference
- Records, Sums, And Tuples
- Functions Generics And Traits
- Pattern Language
- Control Flow And Patterns
- Iteration And Loops
- Failure And Propagation
- Numbers And Collections
- Sets Maps And Sequences
- Keyed Structures
- Trees And Hierarchies
- Standard Library
- Output Formatting And Testing
- Tasks And Scopes
- Compile-Time Evaluation
- Typed Macros
- References And Unsafe
- Worked Programs