Skip to content

Built-in Annotations & CLI Builder

Flame features a comprehensive suite of built-in PascalCase annotations that control runtime evaluation, test case execution, lifecycle setups, and declarative command-line interface (CLI) generation without boilerplate code.


Annotation Category Syntax / Parameters Description
@Application Execution @Application(features: Vector = []) Marks an async function as the main entry point, bootstrapping the Tokio runtime and event loop for non-blocking I/O operations.
@Cli CLI Builder @Cli(name: String, version: String, description: String) Marks an entry function as a CLI application root and passes parsed arguments as cli: Cli.
@Command CLI Builder @Command(name: String, about: String) Marks a function as an executable CLI subcommand handler with auto-mapped flag parameters.
@Docs Documentation @Docs("Markdown string") Provides rich IDE hover documentation for functions, structs, and enums, supporting markdown syntax.
@Embedded Embedded @Embedded(target: String = "arduino-uno", baud: Int = 115200) Defines the infinite hardware loop (void loop()) for zero-cost bare-metal firmware compilation.
@Platform Compilation @Platform("target_substring") Conditionally compiles the annotated declaration only if the active build target matches the given substring. Defaults to the host OS if no target is specified during compilation.
@Requires Dependency @Requires("module_name", ...) Performs a local, function-scoped module import. The module is only usable inside the annotated function (unlike global import).
@Permission Security @Permission("permission", ...) Requests runtime permissions exactly once at program startup. If denied, the program exits. Duplicate permissions across functions are prompted only once.
@Test Testing @Test(timeout: Int = 5000, skip: Bool = false, only: Bool = false, tags: Vector = []) Marks a function as an automated test case executed via flame test. Stripped in release builds.
@Setup Testing @Setup Runs before every test case in the current file. Stripped in release builds.
@Cleanup Testing @Cleanup Runs after every test case in the current file. Stripped in release builds.
@BeforeAll Testing @BeforeAll Runs once before the entire module test suite initiates.
@AfterAll Testing @AfterAll Runs once after all module tests complete execution.
@Ignore Testing @Ignore Skips test execution when running flame test.
@Parameterized Testing @Parameterized([ [arg1, arg2, ...] ]) Executes a test case repeatedly across an array matrix of arguments.

2. Compilation and Documentation Annotations

Section titled “2. Compilation and Documentation Annotations”

Flame allows you to conditionally exclude code blocks (such as functions, structs, or enums) from the final build if the current target does not match the specified platform substring. This is highly useful for OS-specific or target-specific implementations.

@Platform("windows")
fn get_os_name() -> String {
"Windows"
}
@Platform("linux")
fn get_os_name() -> String {
"Linux"
}

If the platform annotation does not match during flame build, the annotated code is entirely stripped from the AST and excluded from the final binary, speeding up compilation and ensuring compatibility. If no explicit target OS is specified during the build, the compiler will automatically default to using the current host operating system.

Dependency Loading and Runtime Permissions

Section titled “Dependency Loading and Runtime Permissions”

Flame utilizes a dynamic, scoped dependency loader alongside a strict runtime permission model. These features are controlled through built-in annotations:

  • @Requires("std.fs", "std.net", ...): Performs a local, function-scoped module import. Unlike a global import statement, the compiler makes the dependency visible only inside the scope of the annotated function. It is securely loaded into memory precisely when the function executes and safely unloaded afterwards.
  • @Permission("fs", "net", ...): Explicitly requests runtime execution permissions from the user.
    • Rules:
      • Permissions are gathered and prompted exactly once at program startup.
      • If the user accepts, the program starts. If denied, execution stops immediately.
      • If multiple functions request the same permission, the user is only asked once.
      • If no @Permission is specified anywhere in the project, permissions are auto-allowed for convenience during prototyping.
      • When used on an @Test function, permissions are automatically granted.

You can provide hover documentation for your types, functions, and variables using the @Docs annotation. The flame language server natively supports markdown formatting inside @Docs, meaning you can write rich text and code blocks!

@Docs("Computes the sum of two numbers.\n\n### Example\n```flame\nlet s = sum(5, 10)\n```")
fn sum(a: Int, b: Int) -> Int {
a + b
}

When hovering over sum in your IDE, it will neatly render the markdown, complete with Flame syntax highlighting in the example block.


3. Declarative CLI Applications (@Cli & @Command)

Section titled “3. Declarative CLI Applications (@Cli & @Command)”

Building robust command-line utilities in traditional systems languages often requires third-party dependency trees, tedious string argument parsing loops, and manual validation code.

Flame introduces native declarative CLI synthesis right into the core language grammar using @Cli, @Command, and structural pattern matching.

Attach @Cli to your main entry function to declare an application root:

@Cli(name: "flame_cli", version: "1.0.0", description: "Flame toolchain & server utility")
fn main(cli: Cli) {
// Flame runtime automatically parses argv terminal flags and wraps them in 'cli'
}
main()

Decorate handler functions with @Command to expose them as valid command terminal options. The parameter signatures of your functions automatically dictate argument flag parsing rules:

Parameter Type & Default Terminal CLI Equivalent Parsing Behavior
release: Bool = false --release (Flag) Converts boolean parameters into terminal presence flags.
target: String = "debug" --target <value> Parses string values following the option flag, defaulting to "debug".
port: Int = 3000 --port <value> Automatically validates and converts input option strings into native integers!

Structural Pattern Matching for Subcommands

Section titled “Structural Pattern Matching for Subcommands”

Inside your @Cli root function, use Flame’s expressive match expressions on the cli: Cli object to destructure flags and dispatch execution cleanly to @Command routines:

match cli {
build { release, target } => build(release, target)
serve { port } => serve(port)
help => print("Usage: app <command> [options]")
_ => print("Unknown command. Run with --help for usage details.")
}

3. Complete Real-World Example: Toolchain & Web Server CLI

Section titled “3. Complete Real-World Example: Toolchain & Web Server CLI”

Below is a production-grade system pattern directly from Flame’s official examples (examples/src/main.fm), demonstrating declarative CLI dispatching (@Cli & @Command) and multithreaded native networking:

import exports
import native.server
@Logger(prefix: "flame-cli")
@Cli(name: "flame_cli", version: "1.0.0", description: "Flame toolchain & high-performance server")
fn main(cli: Cli) {
// Dispatch subcommand execution with declarative pattern matching
match cli {
build { release, target } => build(release, target)
serve { port } => serve(port)
help => print("Help: Use 'build [--release] [--target name]' or 'serve [--port N]'")
_ => print("Error: Unknown command provided.")
}
}
@Command(name: "build", about: "Compile the target workspace project")
fn build(release: Bool = false, target: String = "debug") {
print($"Building target '{target}', release mode engaged: {release}")
}
@Command(name: "serve", about: "Launch multithreaded HTTP server")
fn serve(port: Int = 3000) {
print($"Starting web server on port {port}...")
let app = await server.init()
app.get("/", () {
"Welcome to Flame Multithreaded Web Server & CLI Tool!"
})
app.get("/about", () {
"Built natively on top of Rust, Axum, and Tokio!"
})
fn create_user(body: String) -> String {
print($"Received incoming POST data: {body}")
return $"Successfully created record for payload: {body}"
}
app.post("/users", create_user)
await app.listen(port)
}

When compiled or executed with flame run, your Flame program instantly becomes an interactive CLI tool:

Terminal window
# Execute build subcommand with flag overrides
flame run -- build --release --target production
# Output: Building target 'production', release mode engaged: true
# Launch web server on custom HTTP port
flame run -- serve --port 8080
# Output: Starting web server on port 8080...