Skip to content

Annotations & Metaprogramming (std.annotation)

The std.annotation module delivers Flame’s built-in metaprogramming engine. It provides custom annotations with deep reflection capabilities, allowing them to inspect declarations, extract callable function references, and dynamically wrap or transform function behavior.


Inside any custom annotation declaration, call annotation.context() to retrieve the current AnnotationContext:

import std.annotation
annotation Route(path: String) {
let ctx = annotation.context()
print($"Decorated symbol: {ctx.target.name}")
print($"Declaration kind: {ctx.target.kind}")
print($"Compiler version: {ctx.compiler.version}")
print($"Target platform: {ctx.build.platform}")
}
@Route(path = "/users")
fn list_users() -> String {
return "users"
}

Returns the active AnnotationContext populated with metadata about the annotated target declaration and the compilation environment.

import std.annotation
annotation Example {
let ctx: AnnotationContext = annotation.context()
}

The root metadata object returned by annotation.context():

export struct AnnotationContext {
target: TargetMetadata
compiler: CompilerInfo
module: ModuleInfo
build: BuildInfo
}
Field Type Description
target TargetMetadata Reflection metadata and operations on the decorated declaration.
compiler CompilerInfo Information about the active Flame compiler toolchain.
module ModuleInfo Identification and path of the current module file.
build BuildInfo Compilation target, release mode, platform OS, and architecture.

Represents the symbol (function, struct, enum, or variable) to which the annotation is applied:

export struct TargetMetadata {
name: String
kind: String
parameters: [ParameterInfo]
return_type: String
annotations: [AnnotationInfo]
}
Property Type Description
name String The identifier of the annotated symbol (e.g. "fetch_user").
kind String The declaration kind: "function", "struct", "enum", or "variable".
parameters [ParameterInfo] An ordered list of parameter metadata (for functions).
return_type String Return type signature string (e.g. "String", "Int", or "Nil").
annotations [AnnotationInfo] Array of all annotations attached to this target declaration.

Returns a callable reference to the annotated function.

  • When invoked, ref() executes the target function’s underlying body without re-triggering attached annotations (preventing recursive re-entrancy).
  • Ideal for web router registration, event dispatchers, and task queues.
annotation Route(path: String) {
let ctx = annotation.context()
let handler = ctx.target.ref()
// handler can now be stored in a router table and called on demand
}

transform(transformer: Unknown) -> Unknown

Section titled “transform(transformer: Unknown) -> Unknown”

Wraps or transforms the annotated function. Flame supports two transformer signatures:

  1. Direct Interceptor Closure: Receives the original callable reference as its first argument, followed by the target function’s parameters:

    ctx.target.transform((ref, arg1: String) {
    print($"Before calling {ctx.target.name}")
    let result = ref(arg1)
    print($"After calling {ctx.target.name}")
    return result
    })
  2. Higher-Order Factory Closure: Receives the original callable reference and returns a replacement closure:

    ctx.target.transform((ref) {
    return (arg1: String) {
    let result = ref(arg1)
    return $"[WRAPPED: {result}]"
    }
    })

Describes a parameter declared on the annotated function:

export struct ParameterInfo {
name: String
type: String
has_default: Bool
is_ref: Bool
is_mut: Bool
}
Field Type Description
name String Parameter name identifier.
type String Type annotation as written in code (or "Unknown" if untyped).
has_default Bool Whether a default value expression is specified.
is_ref Bool true if passed by reference (&).
is_mut Bool true if mutable (mut or &mut).

Describes an annotation attached to the declaration:

export struct AnnotationInfo {
name: String
args: [String]
}
Field Type Description
name String Annotation name (e.g. "Route", "Logged").
args [String] List of argument expressions supplied to the annotation.

Reflects the executing Flame compiler:

export struct CompilerInfo {
name: String
version: String
}
Field Type Description
name String Always "flame".
version String Toolchain semver string (e.g. "0.5.7").

Reflects the current source file module:

export struct ModuleInfo {
name: String
filepath: String
}
Field Type Description
name String Name of the current file or module.
filepath String File system path to the declaring .fm file.

Reflects target platform compilation settings:

export struct BuildInfo {
target: String
mode: String
platform: String
arch: String
features: [String]
}
Field Type Example Values Description
target String "native", "web", "wasm" Compilation target architecture.
mode String "debug", "release" Active build optimization mode.
platform String "linux", "darwin", "windows" Host operating system.
arch String "x86_64", "aarch64" CPU architecture.
features [String] ["threads", "simd"] Enabled compiler feature flags.

Use Case 1: Web Router Handler Registration (target.ref())

Section titled “Use Case 1: Web Router Handler Registration (target.ref())”

In modern backend frameworks, annotations are used to register route endpoints directly into a routing table without manual boilerplate:

import std.annotation
let route_table: [Formula] = []
export annotation GET(path: String) {
let ctx = annotation.context()
let handler = ctx.target.ref()
route_table.push(formula {
method: "GET",
path: path,
name: ctx.target.name,
handler: handler
})
}
// Declare endpoints
@GET(path = "/api/v1/health")
fn get_health() -> String {
return "ok"
}
@GET(path = "/api/v1/users")
fn get_users() -> String {
return "{\"users\": [\"Alice\", \"Bob\"]}"
}
// Dispatch incoming request
fn dispatch_request(path: String) -> String {
for route in route_table {
if route.path == path {
let handler = route.handler
return handler()
}
}
return "404 Not Found"
}
print(dispatch_request("/api/v1/health")) // Output: "ok"

Use Case 2: Function Wrapping & Interception (target.transform())

Section titled “Use Case 2: Function Wrapping & Interception (target.transform())”

Use ctx.target.transform() to wrap functions with logging, authentication checks, or result formatting:

import std.annotation
export annotation Logged {
let ctx = annotation.context()
ctx.target.transform(
(ref, msg: String) {
print($"[AUDIT START] Invoking '{ctx.target.name}' with payload: {msg}")
let result = ref(msg)
print($"[AUDIT END] '{ctx.target.name}' completed.")
return $"[LOGGED: {result}]"
}
)
}
@Logged
fn submit_order(order_id: String) -> String {
return $"Order #{order_id} processed"
}
let res = submit_order("9942")
print(res)
// Output:
// [AUDIT START] Invoking 'submit_order' with payload: 9942
// [AUDIT END] 'submit_order' completed.
// [LOGGED: Order #9942 processed]

Use Case 3: Performance Timing & Profiling

Section titled “Use Case 3: Performance Timing & Profiling”

Automatically time any function execution with zero boilerplate:

import std.annotation
import std.time
export annotation Benchmark {
let ctx = annotation.context()
ctx.target.transform(
(ref, n: Int) {
let start = time.now()
let result = ref(n)
let elapsed = time.since(start)
print($"[BENCHMARK] {ctx.target.name}({n}) finished in {elapsed}ms")
return result
}
)
}
@Benchmark
fn compute_fibonacci(n: Int) -> Int {
if n <= 1 { return n }
return compute_fibonacci(n - 1) + compute_fibonacci(n - 2)
}

Flame provides a built-in, first-class @Benchmark annotation and dedicated CLI runner (flame bench). Unlike a simple timing wrapper, the benchmark engine performs automated warmup runs, executes repeated measurement iterations using a zero-allocation monotonic hardware clock, and outputs detailed statistical profiles.

Decorate any parameterless function with @Benchmark:

@Benchmark
fn json_parse() {
let data = parse_json(input)
}

Pass configuration parameters directly to @Benchmark:

Parameter Type Default Description
warmup Int 10 Number of unmeasured warmup iterations to prime caches and branch predictors.
iterations Int 100 Number of timed measurement iterations.
group String "" Grouping identifier for automated comparative benchmark tables.
name String Function Name Custom human-readable label for reporting.
@Benchmark(
warmup: 100,
iterations: 1000,
group: "json",
name: "Standard JSON Parser"
)
fn benchmark_standard_json() {
let parsed = json.read("dataset.json")
}
@Benchmark(
warmup: 100,
iterations: 1000,
group: "json",
name: "Fast Streaming JSON"
)
fn benchmark_fast_json() {
let parsed = json.fromJson(raw_bytes)
}

Execute every benchmark across your project using:

Terminal window
flame bench

Or target a specific benchmark file:

Terminal window
flame bench tests/json_bench.fm

Flame’s benchmark engine generates comprehensive statistical metrics for every benchmark:

[PASS] @Benchmark benchmark_standard_json
Benchmark: Standard JSON Parser
Warmup 100 iterations
Iterations 1,000 iterations
Time
total 182.43 ms
avg 18.24 µs
min 15.81 µs
max 31.92 µs
p50 17.92 µs
p95 21.44 µs
p99 26.73 µs
Throughput
54,812 ops/sec
Memory
allocated 2.41 MB
per op 246 B
Result: PASS
──────────────────────────────────────────────────────────
Benchmark Group: json
Benchmark time/op ops/sec
──────────────────────────────────────────────────────────
Fast Streaming JSON 11.02 µs 90,744
Standard JSON Parser 18.24 µs 54,812
──────────────────────────────────────────────────────────
improvement +65.5%
──────────────────────────────────────────────────────────

Annotations can decorate structs and enums to inspect schema structures for ORMs or serializers:

import std.annotation
let registered_entities: [Formula] = []
export annotation Entity(table: String) {
let ctx = annotation.context()
registered_entities.push(formula {
symbol: ctx.target.name,
kind: ctx.target.kind,
table: table
})
}
@Entity(table = "accounts")
struct Account {
id: Int
email: String
is_active: Bool
}
print($"Registered table: {registered_entities[0].table} for struct {registered_entities[0].symbol}")
// Output: Registered table: accounts for struct Account

Use Case 5: Platform & Architecture Guards

Section titled “Use Case 5: Platform & Architecture Guards”

Use ctx.build and ctx.compiler to validate target platform requirements at declaration time:

import std.annotation
export annotation LinuxOnly {
let ctx = annotation.context()
if ctx.build.platform != "linux" {
panic($"Function '{ctx.target.name}' is only supported on Linux! Current OS: {ctx.build.platform}")
}
}
@LinuxOnly
fn initialize_epoll_driver() {
print("Linux epoll driver initialized.")
}

Feature Description
annotation.context() Retrieves active AnnotationContext (restricted to annotation declarations).
ctx.target.ref() Extracts a callable function reference without re-triggering annotations.
ctx.target.transform() Wraps target functions with direct interceptor or factory closures.
ctx.target.* Introspects target symbol name, kind, parameters, return_type, and annotations.
ctx.compiler.* Accesses toolchain name and version.
ctx.build.* Inspects target architecture, OS platform (linux, darwin, windows), and build mode.