Skip to content

CNL Quick Reference

This page is a comprehensive reference for Aster CNL (Controlled Natural Language) syntax. All examples use the English (EN_US) keyword set unless noted otherwise.

Module Declaration

Every policy begins with exactly one module declaration. The module name is a dot-separated identifier that ends with a period.

Module <Name>.

Examples:

aster
Module pricing.
Module Loan.Approval.
Module Insurance.Auto.Quote.

The module name is used to address the policy when deploying and evaluating via the REST API.

Cross-Module References

A module can reuse a rule published by another team with Use. Pin a specific version with version <N> and bind a local alias with as <Name>; call the imported rule through the alias (<Name>.<rule>).

aster
Module billing.checkout.

Use risk.Scoring version 2 as Score.

Rule approve given amount as Int, produce Text:
  If amount less than 1000
    Return "auto".
  Return "review".

The referenced module must be published as a library version visible to your tenant. Pinning a version keeps your policy stable when the upstream team ships updates. The same clause works in every locale — 引用 risk.Scoring 版本 2 作为 Score。 / verwende risk.Scoring version 2 als Score.

Rule Definition

A rule is a named function with typed parameters and a return type. The body is an indented block of statements.

Rule <name> given <param> as <Type>, produce <ReturnType>:
  <body>
  • given introduces the parameter list.
  • Each parameter is written as <name> as <Type>.
  • Multiple parameters are separated by commas.
  • produce declares the return type.
  • The colon at the end of the signature opens the body block.

Example:

aster
Rule calculateDiscount given amount as Int, tier as Text, produce Int:
  If tier equals to "gold"
    Return amount times 20 divided by 100.
  If tier equals to "silver"
    Return amount times 10 divided by 100.
  Return 0.

Rules with No Parameters

When a rule takes no parameters, omit the given clause:

aster
Rule defaultRate produce Float:
  Return 3.5.

Rules with Struct Parameters

Parameters can use user-defined struct types:

aster
Define Applicant has creditScore as Int.

Rule evaluateApplicant given applicant as Applicant, produce Bool:
  If applicant.creditScore at least 700
    Return true.
  Return false.

Entry Rule

When a module has several rules, mark the main entry point with the @entry annotation so callers don't have to specify which rule to run. The annotation can sit on the same line as Rule or on its own line above it.

aster
Module loan.approval.

Define Applicant has creditScore as Int.

Rule scoreFloor produce Int:
  Return 650.

@entry
Rule decide given applicant as Applicant, produce Text:
  If applicant.creditScore at least 700
    Return "approved".
  Return "rejected".

A module may have at most one @entry rule. Without it, a single-rule module runs that rule by default; a multi-rule module requires the caller to name one.

Data / Struct Definitions

Use Define to declare a named record type with typed fields. Fields are separated by commas. The definition ends with a period.

Define <Name> has <field> as <Type>, <field2> as <Type2>.

Examples:

aster
Define Applicant has name as Text, age as Int, creditScore as Int.
Define Vehicle has make as Text, year as Int, value as Int.
Define Address has street as Text, city as Text, postalCode as Text.

Struct types can be used as parameter types, return types, and field types in other structs:

aster
Define Customer has name as Text, address as Address.

Type System

Aster CNL provides five built-in primitive types and supports user-defined struct types.

Primitive Types

TypeDescriptionExample values
IntInteger number0, 42, -7
FloatFloating-point number3.14, 0.5, -1.0
TextString literal (double-quoted)"hello", "gold"
BoolBoolean valuetrue, false

DateTime Inference

DateTime is not a keyword you write in source code. The compiler infers DateTime as the type for fields whose names match temporal patterns (e.g. createdAt, birthday, expiryDate). You do not need to declare it explicitly.

Custom Types (Structs)

Any name introduced by a Define declaration becomes a valid type:

aster
Define Policy has premium as Int, deductible as Int.

Rule quote given age as Int, produce Policy:
  If age less than 25
    Return Policy with premium set to 500, deductible set to 1000.
  Return Policy with premium set to 300, deductible set to 500.

Control Flow

If Statements

Conditional logic uses If followed by a condition. The body must be indented.

If <condition>
  <body>

If statements can be chained. The first branch whose condition evaluates to true executes, and its Return statement returns a value from the rule.

aster
Rule classify given score as Int, produce Text:
  If score at least 90
    Return "excellent".
  If score at least 70
    Return "good".
  If score at least 50
    Return "average".
  Return "poor".

Nested Conditions

Conditions can be nested by increasing indentation:

aster
Define Applicant has creditScore as Int.

Rule evaluate given applicant as Applicant, tier as Text, produce Bool:
  If applicant.creditScore at least 700
    If tier equals to "premium"
      Return true.
  Return false.

Expressions and Operators

Arithmetic Operators

OperatorDescriptionExample
plusAdditionamount plus 10
minusSubtractionprice minus discount
timesMultiplicationquantity times unitPrice
divided byDivisiontotal divided by count

Arithmetic expressions follow standard precedence: times and divided by bind tighter than plus and minus. Use grouping where needed for clarity.

Comparison Operators

OperatorDescriptionExample
greater thanGreater thanage is greater than 18
less thanLess thanscore is less than 50
at leastGreater than or equalincome is at least 30000
at mostLess than or equalbalance is at most 0
equals to / is equal toEqualitytier is equal to "gold"

You can write an optional is before any comparator for fully natural English — score is at least 700 reads the same as score at least 700 and compiles identically. Use whichever feels clearer; both are valid.

Logical Operators

OperatorDescriptionExampleStatus
notLogical NOTnot isExpired✅ Available
andLogical ANDage at least 18 and income at least 30000✅ Available
orLogical ORtier equals to "gold" or tier equals to "platinum"✅ Available

not negates a boolean condition:

aster
Rule isActive given expired as Bool, produce Bool:
  If not expired
    Return true.
  Return false.

and requires both conditions to hold; or requires either. and binds tighter than or, so x or y and z reads as x or (y and z).

aster
Define Applicant has age as Int, creditScore as Int.

Rule eligible given applicant as Applicant, produce Bool:
  If applicant.age at least 18 and applicant.creditScore at least 650
    Return true.
  Return false.

Construction Expressions

To return a value of a struct type, use a construction expression with with <field> set to <value>:

<TypeName> with <field> set to <value>, <field2> set to <value2>

Example:

aster
Define Quote has premium as Int, deductible as Int.

Rule calculateQuote given vehicleValue as Int, year as Int, produce Quote:
  If year less than 2015
    Return Quote with premium set to vehicleValue times 5 divided by 100, deductible set to 1000.
  Return Quote with premium set to vehicleValue times 3 divided by 100, deductible set to 500.

Each <field> set to <value> clause assigns one field. Multiple clauses are separated by commas after the with keyword. All fields declared on the struct should be assigned.

Field Access

Access fields on a struct parameter using dot notation:

applicant.creditScore
vehicle.year
address.city

Field access can be used in conditions, arithmetic, and as arguments to construction expressions.

Multi-Language Support

Aster CNL supports multiple locales. The same logical policy is expressed using locale-specific keywords. The following table shows keyword equivalents across supported locales.

ConceptEnglish (EN_US)Chinese (ZH_CN)German (DE_DE)
ModuleModule模块Modul
RuleRule规则Regel
Givengiven给定gegeben
As (type)asals
Produceproduce产出liefert
DefineDefine定义Definiere
Hashas包含hat
IfIf如果wenn
Andandund
Ororoder
Equalsequals to等于entspricht
Set...toset ... to将 ... 设为setze ... auf
ReturnReturn返回gib zurueck

The compiler accepts a lexicon parameter that tells it which keyword set to use. All locales compile to the same core representation.

Complete Examples

Example 1: Loan Eligibility

A rule that checks multiple criteria before approving a loan application.

aster
Module Loan.Approval.

Define Applicant has name as Text, age as Int, creditScore as Int, income as Int.

Rule isEligible given applicant as Applicant, requestedAmount as Int, produce Bool:
  If applicant.age less than 18
    Return false.
  If applicant.creditScore less than 650
    Return false.
  If applicant.income less than requestedAmount times 3
    Return false.
  Return true.

Example 2: Insurance Quote with Struct Return

A rule that calculates an insurance quote and returns a structured result.

aster
Module Insurance.Auto.

Define Vehicle has make as Text, year as Int, value as Int.
Define Quote has premium as Int, deductible as Int, coverage as Text.

Rule generateQuote given vehicle as Vehicle, driverAge as Int, produce Quote:
  If driverAge less than 25
    If vehicle.value greater than 50000
      Return Quote with premium set to 4800, deductible set to 2000, coverage set to "basic".
    Return Quote with premium set to 3200, deductible set to 1500, coverage set to "basic".
  If vehicle.year less than 2015
    Return Quote with premium set to vehicle.value times 4 divided by 100, deductible set to 1000, coverage set to "standard".
  Return Quote with premium set to vehicle.value times 3 divided by 100, deductible set to 500, coverage set to "full".

Example 3: Tiered Pricing with Multiple Rules

A module with a struct definition and a pricing rule that uses text comparison.

aster
Module Pricing.Subscription.

Define Plan has name as Text, monthlyRate as Int, userLimit as Int.

Rule resolvePlan given tier as Text, produce Plan:
  If tier equals to "enterprise"
    Return Plan with name set to "Enterprise", monthlyRate set to 299, userLimit set to 500.
  If tier equals to "team"
    Return Plan with name set to "Team", monthlyRate set to 49, userLimit set to 20.
  Return Plan with name set to "Starter", monthlyRate set to 9, userLimit set to 3.

Example 4: Chinese Locale

The same pricing logic expressed with Chinese keywords.

aster
模块 定价。

定义 报价 包含 单价  整数,折扣  整数。

规则 计算报价 给定 数量  整数,会员等级  文本,产出 报价:
  如果 会员等级 等于 "金牌"
    返回 报价 将 单价 设为 数量 乘 80 除以 100,折扣 设为 20
  如果 会员等级 等于 "银牌"
    返回 报价 将 单价 设为 数量 乘 90 除以 100,折扣 设为 10
  返回 报价 将 单价 设为 数量,折扣 设为 0

Syntax Summary

ConstructPattern
Module declarationModule <Name>.
Struct definitionDefine <Name> has <field> as <Type>, ...
Rule signatureRule <name> given <params>, produce <Type>:
Parameter<name> as <Type>
If conditionIf <condition>
Return valueReturn <expr>.
OtherwiseOtherwise
Local bindingLet <name> be <expr>.
Construction<Type> with <field> set to <value>, ...
Field access<param>.<field>
Equality test<expr> equals to <expr>
Logical AND<expr> and <expr>
Logical OR<expr> or <expr>

Released under the Apache License 2.0.