Structure Tags

Structure tags define the organization of Calor code: modules, functions, and their boundaries.


Modules

Modules are like C# namespaces. They group related functions.

Syntax

Plain Text
§M{id:name]
  // contents
§/M{id]

Example

Plain Text
§M{m001:Calculator]
  // functions go here
§/M{m001]

Rules

  • id must be unique within the file
  • name becomes the C# namespace
  • Every §M must have a matching §/M with the same ID

Functions

Functions are the primary code containers.

Syntax

Plain Text
§F{id:name:visibility]
  §I{type:param]       // inputs (0 or more)
  §O{type]             // output (required)
  §E{effects]          // effects (optional)
  §Q condition         // preconditions (0 or more)
  §S condition         // postconditions (0 or more)
  // body
§/F{id]

Visibility

ValueMeaningC# Equivalent
pubPublicpublic static
priPrivateprivate static

Examples

Simple function:

Plain Text
§F{f001:Add:pub]
  §I{i32:a]
  §I{i32:b]
  §O{i32]
  §R (+ a b)
§/F{f001]

Function with effects:

Plain Text
§F{f001:PrintSum:pub]
  §I{i32:a]
  §I{i32:b]
  §O{void]
  §E{cw]
  §P (+ a b)
§/F{f001]

Function with contracts:

Plain Text
§F{f001:Divide:pub]
  §I{i32:a]
  §I{i32:b]
  §O{i32]
  §Q (!= b 0)
  §R (/ a b)
§/F{f001]

Async Functions

Async functions use §AF instead of §F and automatically wrap return types in Task<T>.

Syntax

Plain Text
§AF{id:name:visibility]
  §I{type:param]       // inputs (0 or more)
  §O{type]             // output (auto-wrapped to Task<T>)
  // body with §AWAIT expressions
§/AF{id]

Examples

Simple async function:

Plain Text
§AF{f001:FetchDataAsync:pub]
  §I{str:url]
  §O{str]
  §B{result] §AWAIT §C{httpClient.GetStringAsync] §A url §/C
  §R result
§/AF{f001]

Emits C#:

C#
public static async Task<string> FetchDataAsync(string url)
{
    var result = await httpClient.GetStringAsync(url);
    return result;
}

Async void function (returns Task):

Plain Text
§AF{f001:ProcessAsync:pub]
  §O{void]
  §AWAIT §C{Task.Delay] §A 1000 §/C
§/AF{f001]

Automatic Task Wrapping

Declared OutputEmitted Return Type
§O{void]Task
§O{i32]Task<int>
§O{str]Task<string>
§O{Task<i32>]Task<int> (no double-wrap)

Async Methods

Async methods in classes use §AMT instead of §MT.

Syntax

Plain Text
§AMT{id:name:visibility]
  §I{type:param]
  §O{type]
  // body
§/AMT{id]

Example

Plain Text
§CL{c001:DataService:pub]
  §AMT{mt001:GetUserAsync:pub]
    §I{i32:id]
    §O{User]
    §B{user] §AWAIT §C{_repository.FindAsync] §A id §/C
    §R user
  §/AMT{mt001]
§/CL{c001]

Modifiers

Async methods support the same modifiers as regular methods:

Plain Text
§AMT{mt001:ProcessAsync:pub:virt]    // public virtual async
§AMT{mt002:HandleAsync:prot:ovr]     // protected override async
§AMT{mt003:ComputeAsync:pub:stat]    // public static async

Await Expression

Use §AWAIT to await async operations.

Syntax

Plain Text
§AWAIT expression                    // Simple await
§AWAIT{false] expression             // await with ConfigureAwait(false)
§AWAIT{true] expression              // await with ConfigureAwait(true)

Examples

Simple await:

Plain Text
§B{data] §AWAIT §C{client.GetAsync] §A url §/C

With ConfigureAwait(false) for library code:

Plain Text
§B{data] §AWAIT{false] §C{client.GetAsync] §A url §/C

Emits: var data = await client.GetAsync(url).ConfigureAwait(false);

Using Await in Conditions and Expressions

Plain Text
§IF{if1] §AWAIT §C{IsValidAsync] §A id §/C
  §P "Valid"
§/I{if1]

§R §AWAIT §C{ComputeAsync] §A x §/C

Lambda Expressions

Lambda expressions create anonymous functions.

Inline Lambda Syntax

For simple expression-body lambdas:

Plain Text
(param) → expression
(param1, param2) → expression
() → expression

Examples

Single parameter:

Plain Text
§B{doubler] (x) → (* x 2)

Emits: var doubler = x => x * 2;

Multiple parameters:

Plain Text
§B{add] (a, b) → (+ a b)

Emits: var add = (a, b) => a + b;

No parameters:

Plain Text
§B{getTime] () → §C{DateTime.Now] §/C

Block Lambda Syntax

For statement-body lambdas, use §LAM/§/LAM:

Plain Text
§LAM{id:param1:type1:param2:type2]
  // statements
§/LAM{id]

Example:

Plain Text
§B{printer] §LAM{lam1:x:i32]
  §P x
  §P (* x 2)
§/LAM{lam1]

Async Lambdas

Add async before parameters:

Plain Text
§LAM{lam1:async:x:i32]
  §B{result] §AWAIT §C{ProcessAsync] §A x §/C
  §R result
§/LAM{lam1]

Delegate Definitions

Delegates define function signatures that can be passed as values.

Syntax

Plain Text
§DEL{id:name]
  §I{type:param]       // parameters (0 or more)
  §O{type]             // return type (optional for void)
  §E{effects]          // effects (optional)
§/DEL{id]

Examples

Calculator delegate:

Plain Text
§DEL{d001:Calculator]
  §I{i32:a]
  §I{i32:b]
  §O{i32]
§/DEL{d001]

Emits: public delegate int Calculator(int a, int b);

Void delegate:

Plain Text
§DEL{d001:Logger]
  §I{str:message]
§/DEL{d001]

Emits: public delegate void Logger(string message);

Delegate with effects:

Plain Text
§DEL{d001:FileProcessor]
  §I{str:path]
  §O{bool]
  §E{fs:rw]
§/DEL{d001]

Event Definitions

Events allow objects to notify subscribers of state changes.

Syntax

Plain Text
§EVT{id:name:visibility:delegateType]
PartDescription
idUnique identifier
nameEvent name
visibilitypub, pri, prot
delegateTypeDelegate type for handlers

Example

Plain Text
§CL{c001:Button:pub]
  §EVT{e001:Click:pub:EventHandler]
  §EVT{e002:ValueChanged:pub:EventHandler<ValueChangedEventArgs>]
§/CL{c001]

Emits:

C#
public class Button
{
    public event EventHandler Click;
    public event EventHandler<ValueChangedEventArgs> ValueChanged;
}

Event Subscribe/Unsubscribe

Use §SUB and §UNSUB to add or remove event handlers.

Syntax

Plain Text
§SUB eventRef handlerRef      // Subscribe
§UNSUB eventRef handlerRef    // Unsubscribe

Examples

Subscribe to event:

Plain Text
§SUB button.Click OnButtonClick

Emits: button.Click += OnButtonClick;

Unsubscribe from event:

Plain Text
§UNSUB button.Click OnButtonClick

Emits: button.Click -= OnButtonClick;

Subscribe with lambda:

Plain Text
§SUB button.Click (sender, e) → §P "Clicked!"

Input Parameters

Input parameters define function arguments.

Syntax

Plain Text
§I{type:name]

Examples

Plain Text
§I{i32:x]           // int x
§I{str:name]        // string name
§I{bool:flag]       // bool flag
§I{?i32:maybeVal]   // int? maybeVal (nullable)

Multiple Parameters

Plain Text
§F{f001:Add:pub]
  §I{i32:a]
  §I{i32:b]
  §I{i32:c]
  §O{i32]
  §R (+ (+ a b) c)
§/F{f001]

Output Type

Every function must declare its output type.

Syntax

Plain Text
§O{type]

Examples

Plain Text
§O{void]     // returns nothing
§O{i32]      // returns int
§O{str]      // returns string
§O{?i32]     // returns nullable int
§O{i32!str]  // returns Result<int, string>

Closing Tags

Every structural element must be closed with a matching tag.

Rules

  1. Opening §X{id:...} must have closing §/X{id}
  2. IDs must match exactly
  3. Nesting must be proper (no overlapping scopes)

Correct Nesting

Plain Text
§M{m001:Example]
  §F{f001:Main:pub]
    §L{for1:i:1:10:1]
      §IF{if1] (> i 5)
        §P i
      §/I{if1]
    §/L{for1]
  §/F{f001]
§/M{m001]

Incorrect (Overlapping)

Plain Text
// WRONG: if1 closed after for1
§L{for1:i:1:10:1]
  §IF{if1] (> i 5)
§/L{for1]
  §/I{if1]     // Error: if1 overlaps for1

Tag Reference

OpeningClosingPurpose
§M{id:name]§/M{id]Module
§F{id:name:vis]§/F{id]Function
§AF{id:name:vis]§/AF{id]Async function
§MT{id:name:vis]§/MT{id]Method
§AMT{id:name:vis]§/AMT{id]Async method
§DEL{id:name]§/DEL{id]Delegate definition
§LAM{id:params]§/LAM{id]Lambda (block body)
§EVT{id:name:vis:type]-Event definition
§L{id:var:from:to:step]§/L{id]For loop
§WH{id] cond§/WH{id]While loop
§DO{id]§/DO{id] condDo-while loop
§IF{id] cond§/I{id]Conditional
§C{target]§/CCall (no ID needed)

C# Attributes

C# attributes are preserved during conversion using inline bracket syntax {@Attribute].

Syntax

Plain Text
§CL{id:name]{@AttributeName]
§CL{id:name]{@AttributeName(args)]
§MT{id:name:vis]{@Attr1]{@Attr2]

Examples

Class with routing attributes (ASP.NET Core):

Plain Text
§CL{c001:JoinController:ControllerBase]{@Route("api/[controller]")]{@ApiController]
  §MT{m001:Post:pub]{@HttpPost]
  §/MT{m001]
§/CL{c001]

Property with validation:

Plain Text
§PROP{p001:Email:str:pub]{@Required]{@EmailAddress]
  §GET
  §SET
§/PROP{p001]

Attribute Arguments

StyleSyntaxExample
No args{@Name]{@ApiController]
Positional{@Name(value)]{@Route("api/test")]
Named{@Name(Key="value")]{@JsonProperty(PropertyName="id")]
Mixed{@Name(pos, Key=val)]{@Range(1, 100, ErrorMessage="Invalid")]

Supported Elements

Attributes can be attached to:

  • Classes: §CL{...]{@attr]
  • Interfaces: §IFACE{...]{@attr]
  • Methods: §MT{...]{@attr]
  • Properties: §PROP{...]{@attr]
  • Fields: §FLD{...]{@attr]
  • Parameters: §I{type:name]{@attr]

Generics

Calor supports generic functions, classes, interfaces, and methods using angle bracket syntax.

Type Parameters

Type parameters are declared using <T> suffix syntax after the tag attributes.

Plain Text
§F{id:name:vis}<T>         // Generic function with one type parameter
§F{id:name:vis}<T, U>      // Generic function with two type parameters
§CL{id:name}<T>            // Generic class
§IFACE{id:name}<T>         // Generic interface
§MT{id:name:vis}<T>        // Generic method

Constraints

Type parameter constraints are declared using §WHERE clauses.

Plain Text
§WHERE T : class                    // T must be a reference type
§WHERE T : struct                   // T must be a value type
§WHERE T : new()                    // T must have parameterless constructor
§WHERE T : IComparable<T>           // T must implement interface
§WHERE T : class, IComparable<T>    // Multiple constraints

Generic Type References

Generic types are written inline using angle bracket syntax.

Plain Text
§I{List<T>:items}                   // Parameter of type List<T>
§I{Dictionary<str, T>:lookup}       // Nested generic types
§O{IEnumerable<T>}                  // Generic return type
§FLD{List<T>:_items:pri}            // Generic field type

Examples

Generic identity function:

Plain Text
§F{f001:Identity:pub}<T>
  §I{T:value}
  §O{T}
  §R value
§/F{f001}

Generic class with constraint:

Plain Text
§CL{c001:Repository:pub}<T>
  §WHERE T : class
  §FLD{List<T>:_items:pri}

  §MT{m001:Add:pub}
    §I{T:item}
    §O{void}
    §C{_items.Add} §A item §/C
  §/MT{m001}

  §MT{m002:GetAll:pub}
    §O{IReadOnlyList<T>}
    §R _items
  §/MT{m002}
§/CL{c001}

Generic interface:

Plain Text
§IFACE{i001:IRepository}<T>
  §WHERE T : class
  §MT{m001:Get}
    §I{i32:id}
    §O{T}
  §/MT{m001}
§/IFACE{i001}

Why Explicit Closing Tags?

  1. Unambiguous parsing - No brace-counting needed
  2. ID verification - Compiler catches mismatches
  3. Agent-friendly - Easy to identify scope boundaries
  4. Refactoring safe - IDs survive code movement

Next

  • Types - Type system reference