Expression DSL Reference
1. Overview
Section titled “1. Overview”Expressions define stateless logic that operates on well-typed inputs and produces well-typed outputs.
Expressions may represent:
- conditions;
- validations;
- mappings and transformations;
- calculations;
- derived values;
- routing decisions;
- reusable business logic.
Expressions are designed to be:
- stateless;
- side-effect-free;
- deterministic where possible;
- reusable;
- composable;
- independent from persistence and transport technologies.
Expressions do not directly:
- mutate persistent state;
- access databases;
- perform external I/O;
- own runtime state.
Ocean supports two forms of expressions:
- Explicit Expressions — named reusable expressions defined under
@expression. - Implicit Expressions — inline expression logic embedded directly where it is used.
2. Explicit Expressions
Section titled “2. Explicit Expressions”Explicit expressions are named reusable logic units.
They are defined under:
@expressionA file may contain multiple explicit expression definitions.
General syntax:
@expression
<ExpressionName> context : <name1:DataType1> & <name2:DataType2> & ... input : <name1:DataType1> & <name2:DataType2> & ... output : <name1:DataType1> & <name2:DataType2> & ...
include: <BuiltinRef>
logic <expression logic>Alternatively, an expression may delegate its implementation to external code:
<ExpressionName> context : <name1:DataType1> & ... input : <name1:DataType1> & ... output : <name1:DataType1> & ...
external source: "<file-name>" method: "<method-name>"Each explicit expression uses either:
logic; orexternal.
3. Expression Elements
Section titled “3. Expression Elements”| Element | Description |
|---|---|
@expression |
Starts an expression definition file. |
ExpressionName |
Unique name of the reusable expression. |
context |
Optional typed values supplied from service context. |
input |
Typed input values available to the expression. |
output |
Typed values produced by the expression. |
include |
Makes built-in functions available to the expression. |
logic |
Defines expression logic using the Ocean expression language. |
external |
Delegates implementation to external source code. |
Expression names follow the same naming convention as Ocean datatype names.
Examples:
IsHighPriorityMapToSummaryCalculateDiscountComputeTaxInput and output names follow Ocean field naming conventions.
3.1 Context Bindings
Section titled “3.1 Context Bindings”An explicit expression may declare optional named and typed service-context bindings.
Syntax:
context : <name>:<Datatype>Multiple context bindings are separated using &:
context : requestId:String & actor:UserIdentityContext bindings follow the same name-and-datatype rules as inputs and outputs. They expose only the context values explicitly connected by the surrounding service. Expressions treat those values as read-only and must remain stateless and side-effect-free.
Some expressions instead receive context as an ordinary typed input — for
example input: ctx:Context & req:SignUpInput — rather than through a separate
context : line.
4. Inputs
Section titled “4. Inputs”Expression inputs are named and typed.
Syntax:
input : <name>:<Datatype>Example:
input : order:OrderMultiple inputs are separated using &.
Example:
input : price:Float & quantity:IntAn expression that takes no input declares _:
input : _Each input datatype must resolve to a valid Ocean datatype.
Inputs are read-only from the perspective of the expression.
4.1 Function-Typed Inputs
Section titled “4.1 Function-Typed Inputs”An input may be a function type, written Func<InputType, OutputType>. It is
supplied by the caller and invoked from logic like a call:
RequestHandler input : a:Int & b:Int & requester:Func<MathRequest, MathResponse> output : result:Int logic var req MathRequest req.num1 = a req.num2 = b var res MathResponse res = requester(req) result = res.resValueThis is used, for example, to hand an expression a broker request-response call without coupling it to the transport.
5. Outputs
Section titled “5. Outputs”Expression outputs are named and typed.
Syntax:
output : <name>:<Datatype>Example:
output : result:BooleanMultiple outputs are separated using &.
Example:
output : amount:Float & eligible:BooleanExpressions produce values through their declared outputs.
6. Logic Expressions
Section titled “6. Logic Expressions”A logic block defines an expression using the Ocean expression language.
Syntax:
logic <expression logic>Example:
IsHighPriority input : order:Order output : result:Boolean
logic result = order.priority == "HIGH"Logic may:
- read input values;
- access nested fields;
- declare intermediate values;
- perform calculations;
- evaluate conditions;
- invoke included built-in functions;
- invoke other available expressions;
- assign declared outputs.
Logic must remain stateless and side-effect-free.
6.1 Statement Forms
Section titled “6.1 Statement Forms”A logic block is a sequence of statements, one per line.
Assignment — to an output, an output field, or a local variable:
r = a + br.result = a + br.isValid = trueresult = resA whole value may be assigned when the types match (result = res), or fields
may be assigned individually (r.result = ...).
Local variable declaration — var <name> <Type> introduces a mutable local:
var res MathResponseres.resValue = req.num1 + req.num2result = resBlock conditional — if <condition> then … optional else … end. Branch
bodies contain statements, not a single value:
if b == 0 then r.result = 0 r.isValid = falseelse r.result = a / b r.isValid = trueendif req.reqType == RequestType.time then res.resContent = GetTimeString()endThe inline if <cond> then <value> else <value> form in Section 18 is an
expression that produces a value; the block form above is control flow around
statements.
Error — error "<message>" (or error <ErrorName> for a declared error)
stops evaluation and raises the error to the caller:
if movementItem.quantity <= 0 then error "quantity must be a positive number"end7. External Expressions
Section titled “7. External Expressions”An expression may delegate its implementation to external code.
Syntax:
external source: "<file-name>" method: "<method-name>"Example:
@expression
ComputeTax input : invoice:Invoice output : taxAmount:Float
external source: "tax-rules.go" method: "ComputeTax"External expressions are useful when:
- logic is too complex for inline expression syntax;
- existing implementation code should be reused;
- specialized algorithms are required;
- generated code needs to delegate to user-provided implementation.
The external implementation must respect the same expression contract:
- declared inputs;
- declared outputs;
- stateless behavior;
- no unintended side effects.
8. Built-in Functions
Section titled “8. Built-in Functions”Expressions may include built-in Ocean functions.
Syntax:
include: <name>@<version>Examples:
include: normalizeString@1.0.0include: nowinclude: uuid@latestMultiple include: lines are allowed.
Each include: declaration is defined on one line.
Example:
include: normalizeString@1.0.0include: nowinclude: uuid@latestA built-in reference follows the conceptual format:
<name>@<version>If no version is specified, the latest applicable version is used.
Built-in functions are distinct from @import and the Ocean Repository include mechanism.
include: inside an expression makes expression-language built-ins available to the expression logic.
9. Boolean Expressions
Section titled “9. Boolean Expressions”A Boolean Expression evaluates a condition and produces a Boolean result.
Example:
@expression
IsHighPriority input : order:Order output : result:Boolean
include: normalizeString@1.0.0 include: now include: uuid@latest
logic result = order.priority == "HIGH"Typical uses include:
- FSM guards;
- conditional routing;
- validation;
- filtering;
- runtime decisions.
10. Mapping and Projection
Section titled “10. Mapping and Projection”Expressions may transform one datatype or structure into another.
Example:
@expression
MapToSummary input : order:Order output : summary:OrderSummary
logic summary.id = order.id summary.total = order.amount * order.quantity summary.status = order.statusMappings may:
- copy fields;
- rename values;
- calculate derived fields;
- combine multiple inputs;
- construct output structures.
This makes expressions suitable for explicit transformation logic between typed DSL elements.
11. Computation
Section titled “11. Computation”Expressions may perform calculations.
Example:
@expression
CalculateDiscount input : item:Item output : discount:Float
logic discount = if item.quantity > 10 then 0.2 else 0.0Computations may produce:
- numeric values;
- strings;
- Boolean results;
- compound datatypes;
- multiple typed outputs.
12. Expression Language
Section titled “12. Expression Language”The Ocean expression language supports common constructs for declarative logic.
| Feature | Syntax / Example | Description |
|---|---|---|
| Literals | "Paid", true, 42 |
Constant values. |
| Variables | status, amount, input.name |
Access variables and fields. |
| Element access | items[index], values[key] |
Access a List element or Map value. |
| Conditionals | if x > 0 then "OK" else "Fail" |
Conditional evaluation. |
| Ternary | x > 0 ? "pos" : "neg" |
Short conditional form. |
| Booleans | x and y, not x, x or y |
Logical operations. |
| Comparisons | ==, !=, >, <, >=, <= |
Value comparison. |
| Math | a + b, price * quantity, total % 10 |
Arithmetic operations. |
| Function calls | map(id, status), concat(a, b) |
Invoke functions or expressions. |
| Let bindings | let total = a + b in total * 2 |
Intermediate values. |
| Match / Case | match status { "A" -> x, "B" -> y, _ -> z } |
Exact-match branching where supported. |
| Chaining | validate(input).transform("mode") |
Compose operations. |
Some expression-language constructs may evolve as the parser and generators are extended.
The canonical behavior of each construct should be updated here together with its implementation.
13. Literals
Section titled “13. Literals”Expressions may use literal values.
Examples:
"Paid"true420.2Literal values must be compatible with the datatype expected by the surrounding expression.
14. Variables and Field Access
Section titled “14. Variables and Field Access”Inputs and intermediate values may be referenced by name.
Example:
orderFields are accessed using dot notation:
order.priorityNested access may follow the same model:
order.customer.loyaltyLevelExpressions may also access locally defined intermediate values where supported by the expression language.
14.1 List and Map Element Access
Section titled “14.1 List and Map Element Access”Square brackets read an element from a List or a value from a Map:
result = items[index]result = values[key]The bracket expression is evaluated before access. A list index must evaluate
to Int; a map key must match the key type declared by the map.
Validation and evaluation rules:
- A negative or out-of-range list index produces an evaluation error.
- A missing map key produces an evaluation error.
- Access on a value that is not a
ListorMapis rejected during expression validation. - A non-
Intlist index is rejected during expression validation. - A map key whose type does not match the declared key type is rejected during expression validation.
The current expression grammar supports one level of element access when it is the complete right-hand side of an assignment.
Supported:
result = items[index]result = values[key]Not yet supported:
result = matrix[row][column]result = items[index] + 1result = items[indexes[position]]Chained access, access combined with another expression, and nested access inside the key expression require future grammar support.
15. Boolean Operations
Section titled “15. Boolean Operations”Supported Boolean operations include:
a and ba or bnot aExample:
order.total > 500 and customer.active == true16. Comparisons
Section titled “16. Comparisons”Expressions may compare compatible values using:
==!=><>=<=Example:
order.priority == "HIGH"Example:
item.quantity > 10Comparison operands must be type-compatible.
17. Arithmetic
Section titled “17. Arithmetic”Expressions may perform arithmetic using operators such as:
+-*/%Example:
summary.total = order.amount * order.quantityArithmetic operations require compatible numeric datatypes.
18. Conditional Expressions
Section titled “18. Conditional Expressions”Conditional logic may be expressed inline.
Example:
discount = if item.quantity > 10 then 0.2 else 0.0A short ternary form may also be supported:
result = x > 0 ? "pos" : "neg"Conditional branches must produce compatible result types.
19. Enum Values
Section titled “19. Enum Values”Enum values are accessed through their enum type.
Syntax:
<EnumType>.<value>Example:
TaskLifecycle.inProgressThis makes enum references explicit and avoids ambiguity between enum values and ordinary variables.
20. Expression Composition
Section titled “20. Expression Composition”Explicit expressions may invoke other expressions.
Example:
@expression
IsPreferredCustomer input : customer:Customer output : result:Boolean
logic result = customer.loyaltyLevel == "GOLD"
IsDiscountEligible input : order:Order output : result:Boolean
logic result = order.total > 500 and IsPreferredCustomer(order.customer).resultThis allows complex logic to be composed from smaller reusable expressions.
Expression composition must remain stateless and side-effect-free.
21. Implicit Expressions
Section titled “21. Implicit Expressions”Implicit Expressions are lightweight inline expressions defined directly where they are used.
Unlike explicit expressions, implicit expressions:
- have no reusable name;
- are local to their point of use;
- cannot be referenced elsewhere;
- use the same underlying expression-language concepts.
Typical uses include:
- guards;
- conditions;
- routing decisions;
- one-off transformations.
Conceptual examples include:
if input.amount > 100connect input -> output if input.status == "Ready"value = input.amount * 2For complex or reusable logic, an explicit @expression should be preferred.
The exact embedding syntax depends on the DSL construct in which the implicit expression is used.
22. Explicit vs Implicit Expressions
Section titled “22. Explicit vs Implicit Expressions”| Characteristic | Explicit | Implicit |
|---|---|---|
| Named | Yes | No |
| Reusable | Yes | No |
Defined under @expression |
Yes | No |
| Used inline | Referenced by name | Yes |
| Typed contract | Explicit input/output | Derived from surrounding context |
| Best for | Shared or complex logic | Small local logic |
Both forms use the same conceptual expression language.
23. Use in FSMs
Section titled “23. Use in FSMs”FSMs may use explicit expressions as reusable logic.
Example:
@expression
IsHighValueOrder input : order:Order output : result:Boolean
logic result = order.total > 1000An FSM may then use the expression according to FSM expression invocation syntax.
Expressions are useful in FSMs for:
- guards;
- calculations;
- validation;
- decision logic;
- transformations.
Because expressions are stateless, state transitions remain the responsibility of the FSM.
24. Use in Components
Section titled “24. Use in Components”Components may use expressions for:
- transformation between connected ports;
- mapping;
- conditional routing;
- reusable calculations.
Conceptually:
use expression MyMapperA mapper expression may transform a source datatype into the datatype required by a target connection.
The exact component mapper syntax should be finalized together with @component implementation.
25. Use in Services
Section titled “25. Use in Services”Services may use expressions as stateless logic units within service orchestration.
Expressions may provide:
- validation;
- transformation;
- calculations;
- decision logic;
- reusable business rules.
The service controls orchestration and side effects, while expressions remain pure logic units.
The exact service invocation and connection semantics are defined by @service.
26. Imports
Section titled “26. Imports”An @expression file may import reusable definitions from the Ocean Repository.
Supported imported item types include:
datatype;expression.
Example:
@expression
@import datatype O.common.math.Vector@2.0.0 as Vector@import expression O.common.logic.DotProduct@2.1 as Dot
ComputeNorm input : v:Vector output : norm:Float
logic # use Dot(...) as part of logicImported datatypes may be used in:
input:and:
output:Imported expressions may be invoked from a logic block using their alias.
Every imported datatype or expression requires an as <alias> clause and must
be referenced through that alias.
Reusable definitions may also be made available through the supported Ocean include mechanism.
27. Complete Example
Section titled “27. Complete Example”A complete @expression file
(ocean-examples/0004-answer-sync/40-ans-expression.ocn):
@expression
HandleDateTimeRequest input: req:TimeDateRequest output: result:TimeDateResponse logic var res TimeDateResponse res.resType = req.reqType if req.reqType == RequestType.time then res.resContent = GetTimeString() end if req.reqType == RequestType.date then res.resContent = GetDateString() end result = res
GetTimeString input: _ output: result:String logic nowTime = nowTimeString() result = nowTime
GetDateString input: _ output: result:String logic nowDate = nowDateString() result = nowDate
GetDayString input: _ output: result:String logic today = today() result = today
GetDayTip input: _ output: result:String logic dayTip = tipOfTheDay() result = dayTip
PrettyTime input: i:String output: o:String logic o = StringConcat2("⏰ ", i)
PrettyDate input: i:String output: o:String logic o = StringConcat2("📅 ", i)
PrettyTip input: i:String output: o:String logic o = StringConcat2("💡 ", i)
TimeAnswerToString input: i:TimeAnswer output: o:String logic o = "Today is " o = StringConcat2(o, i.day) o = StringConcat2(o, "! ") o = StringConcat2(o, i.date) o = StringConcat2(o, " ") o = StringConcat2(o, i.time) o = StringConcat2(o, " ") o = StringConcat2(o, i.tip)This example demonstrates:
- multiple expressions in one file;
input: _for an expression that takes no input;varlocal declarations and whole-value output assignment (result = res);- block
if <cond> then … endcontrol flow; - enum comparison (
req.reqType == RequestType.time); - calls to other expressions (
GetTimeString()) and to built-in helpers (nowTimeString(),today(),tipOfTheDay(),StringConcat2(...)); - typed inputs and outputs, including user-defined datatypes.
The example does not use external, include:, or expression imports; see
Sections 7, 8, and 26 for those. Note that helper functions such as
nowTimeString() and StringConcat2(...) are called directly here without an
include: line.
28. Rules and Constraints
Section titled “28. Rules and Constraints”The following rules apply:
- An explicit expression file starts with
@expression. - A file may define multiple expressions.
- Expression names follow Ocean datatype naming conventions.
- Optional context bindings are named and typed, separated using
&, and exposed read-only to expression logic. - Inputs and outputs are named and typed.
- Multiple inputs and outputs are separated using
&. - An expression that takes no input declares
input : _. - An input may be a function type
Func<InputType, OutputType>, invoked fromlogiclike a call. logicis a sequence of statements: assignments,var <name> <Type>declarations, blockif <cond> then … [else …] endcontrol flow, anderror "<message>"/error <ErrorName>.- Expressions are stateless.
- Expressions are side-effect-free.
- Expressions do not directly access databases or external I/O.
- An explicit expression uses either a
logicblock or anexternalblock. logiccontains Ocean expression-language logic.externaldelegates implementation to external code.- External expressions require
source:andmethod:. - Multiple
include:lines are allowed. - Each
include:declaration is defined on one line. - Explicit expressions may compose other expressions.
- Implicit expressions are local and non-reusable.
- Enum values are referenced through their enum type.
ListandMapelement access follows the validation and current grammar limitations defined in Section 14.1.- Imported datatypes and expressions require explicit aliases.
- Imported datatypes and expressions may be used through their aliases.
29. Related Knowledge
Section titled “29. Related Knowledge”The @expression DSL is related to:
dsl.datatype— defines the type system used by expression inputs, outputs, variables, and values.dsl.fsm— uses expressions for reusable conditions, calculations, validation, and transition logic.dsl.component— may use expressions for mapping, transformation, and routing between component elements.dsl.service— uses expressions as stateless logic within service orchestration.dsl.import— defines the mechanism for importing selected datatype and expression definitions from the Ocean Repository.dsl.include— defines the mechanism for including reusable definitions from the Ocean Repository.
These semantic relationships are declared in the document metadata.