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.
1. Built-in Annotations Reference Table
Section titled “1. Built-in Annotations Reference Table”| 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”Conditional Compilation (@Platform)
Section titled “Conditional Compilation (@Platform)”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 globalimportstatement, 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
@Permissionis specified anywhere in the project, permissions are auto-allowed for convenience during prototyping. - When used on an
@Testfunction, permissions are automatically granted.
- Rules:
Rich IDE Documentation (@Docs)
Section titled “Rich IDE Documentation (@Docs)”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.
The @Cli Root Annotation
Section titled “The @Cli Root Annotation”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()Subcommand Handlers (@Command)
Section titled “Subcommand Handlers (@Command)”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 exportsimport 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)}Running the Application from the Shell
Section titled “Running the Application from the Shell”When compiled or executed with flame run, your Flame program instantly becomes an interactive CLI tool:
# Execute build subcommand with flag overridesflame run -- build --release --target production# Output: Building target 'production', release mode engaged: true
# Launch web server on custom HTTP portflame run -- serve --port 8080# Output: Starting web server on port 8080...