Rich Communication Language (RCL) - Formal Specification
Section titled “Rich Communication Language (RCL) - Formal Specification”1. Introduction
Section titled “1. Introduction”This document provides the formal specification for the Rich Communication Language (RCL) using an Extended Backus-Naur Form (EBNF)-like notation.
RCL is a data language designed to express any JSON-representable structure through a human-friendly syntax. It provides a generic Section/Attribute model where sections correspond to objects and can represent any hierarchical data. The language emphasizes simplicity, readability, and extensibility.
Design Philosophy
Section titled “Design Philosophy”- Generic Data Language: Any JSON structure can be expressed using Sections (objects) and Attributes (properties)
- Indentation-based: Blocks are defined by indentation (like Python/YAML), no explicit end keywords
- Extensible: New section types can be added without changing the core syntax
- Type-aware: Built-in type tags for common data types with validation
Notation Conventions
Section titled “Notation Conventions”RuleName ::= Definition: Defines a rule'literal': Literal string or keyword (e.g.,'agent',':')TERMINAL_NAME: Terminal symbol/token (e.g.,IDENTIFIER,STRING)RuleName: Non-terminal symbol referenceA | B: Alternative (A or B)(A B): Sequence of A followed by BA?: Zero or one occurrence (optional)A*: Zero or more occurrencesA+: One or more occurrences// comment: Explanatory comments
2. Lexical Specification (Terminals)
Section titled “2. Lexical Specification (Terminals)”2.1 Block Delimiters
Section titled “2.1 Block Delimiters”RCL uses indentation-based blocks (Python-style) without explicit end keywords.
INDENT ::= // Increase in indentation levelDEDENT ::= // Decrease in indentation level2.2 Hidden Terminals
Section titled “2.2 Hidden Terminals”WS ::= /[ ]+/ // Whitespace (spaces/tabs), not newlinesNL ::= /[]+/ // NewlinesSL_COMMENT ::= /#.*/ // Single-line comments2.3 Common Terminals
Section titled “2.3 Common Terminals”IDENTIFIER ::= /[A-Z]([A-Za-z0-9-_]|(\s(?=[A-Z0-9]))*/ // Title Case with spacesATTRIBUTE_KEY ::= /[a-z][a-zA-Z0-9_]*/ // lowerCamelCaseSECTION_TYPE ::= /[a-z][a-zA-Z0-9]*/ // lowercase section typesVARIABLE ::= /@[a-zA-Z_][a-zA-Z0-9_]*/ // @variablePROPERTY_ACCESS ::= VARIABLE ('.' ATTRIBUTE_KEY)* // @obj.propertyATOM ::= /:[a-zA-Z_][a-zA-Z0-9_]*/ // :symbolSTRING ::= /"(\.|[^"\])*"/ // Double-quoted stringsTRIPLE_STRING_DELIM ::= /"""/ // Triple quote delimiterNUMBER ::= /[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?/ // Numbers with optional decimals/exponentsISO_DURATION ::= /(P((\d+Y)|(\d+M)|(\d+W)|(\d+D)|(T((\d+H)|(\d+M)|(\d+(\.\d+)?S))+))+)|([0-9]+(\.[0-9]+)?s)/SPREAD ::= /\.\.\./ // Spread operator2.4 String Interpolation
Section titled “2.4 String Interpolation”INTERPOLATION_START ::= /#\{/INTERPOLATION_END ::= /\}/2.5 Embedded Code Terminals
Section titled “2.5 Embedded Code Terminals”EMBEDDED_CODE ::= /\$((js|ts)?>)\s*[^]*/ // $js> code or $> exprMULTI_LINE_CODE_START ::= /\$((js|ts)?)>>>/ // $js>>> or $>>>MULTI_LINE_CODE_END ::= /<\$/ // End marker2.6 Multi-line String Terminals
Section titled “2.6 Multi-line String Terminals”MULTILINE_STR_CLEAN ::= /\|\s*$/ // | (clean)MULTILINE_STR_TRIM ::= /\|-\s*$/ // |- (trim trailing)MULTILINE_STR_PRESERVE ::= /\+\|\s*$/ // +| (preserve leading)MULTILINE_STR_PRESERVE_ALL ::= /\+\|\+\s*$/ // +|+ (preserve all)MULTILINE_STR_END ::= /^\s*\|$/ // Line with only |2.7 Type Tag Terminals
Section titled “2.7 Type Tag Terminals”TYPE_TAG_NAME ::= /[a-zA-Z]+/ // email, phone, url, etc.3. Syntactic Specification (Parser Rules)
Section titled “3. Syntactic Specification (Parser Rules)”3.0 Core Value Rules
Section titled “3.0 Core Value Rules”BooleanLiteral ::= 'True' | 'Yes' | 'On' | 'False' | 'No' | 'Off'
NullLiteral ::= 'Null' | 'None' | 'Void'
PrimitiveValue ::= STRING | MultiLineString | NUMBER | BooleanLiteral | NullLiteral | ATOM | TypeTag
InterpolatedContent ::= PlainText | (INTERPOLATION_START (VARIABLE | PROPERTY_ACCESS | Value) INTERPOLATION_END)
TypeTag ::= '<' TYPE_TAG_NAME (STRING | NUMBER | IDENTIFIER | ISO_DURATION) ('|' STRING)? '>'
Value ::= PrimitiveValue | IDENTIFIER | VARIABLE | PROPERTY_ACCESS | List | Dictionary | EmbeddedCode
ContextualizedValue ::= Value ('with' ParameterList)?
Parameter ::= ATTRIBUTE_KEY ':' Value | Value // Positional parameter
ParameterList ::= Parameter (',' Parameter)*3.1 Collection Rules
Section titled “3.1 Collection Rules”List ::= ParenthesesList | InlineList | BlockList
ParenthesesList ::= '(' (Value (',' Value)*)? ')'
InlineList ::= Value (',' Value)+ // 2+ items, parentheses optional
BlockList ::= INDENT (BlockListItem)+ DEDENT
BlockListItem ::= '-' Value
Dictionary ::= BraceDictionary | BlockDictionary
BraceDictionary ::= '{' (DictEntry (',' DictEntry)*)? '}'
BlockDictionary ::= INDENT (DictEntry)+ DEDENT
DictEntry ::= (ATTRIBUTE_KEY | STRING) ':' Value3.2 String Rules
Section titled “3.2 String Rules”MultiLineString ::= ( // Pipe-style (MULTILINE_STR_CLEAN | MULTILINE_STR_TRIM | MULTILINE_STR_PRESERVE | MULTILINE_STR_PRESERVE_ALL) INDENT StringContent DEDENT MULTILINE_STR_END ) | ( // Triple-quote style TRIPLE_STRING_DELIM (InterpolatedContent)* TRIPLE_STRING_DELIM )
StringContent ::= // Raw text content with proper indentation handling
3.3 Embedded Code Rules
Section titled “3.3 Embedded Code Rules”EmbeddedCode ::= SingleLineCode | MultiLineCode
SingleLineCode ::= EMBEDDED_CODE
MultiLineCode ::= MULTI_LINE_CODE_START INDENT CodeContent DEDENT MULTI_LINE_CODE_END
CodeContent ::= // Raw code content3.4 Section Rules
Section titled “3.4 Section Rules”Section ::= SECTION_TYPE IDENTIFIER? ParameterList? (INDENT (SpreadDirective | Attribute | Section | MatchBlock | Value)* DEDENT)?
SpreadDirective ::= SPREAD IDENTIFIER
Attribute ::= ATTRIBUTE_KEY ':' Value
MatchBlock ::= 'match' Value INDENT (MatchCase)+ DEDENT
MatchCase ::= (STRING | NUMBER | ATOM) '->' Consequence | ':default' '->' Consequence
Consequence ::= ContextualizedValue | FlowInvocation | FlowTermination
FlowInvocation ::= 'start' IDENTIFIER ('with' ParameterList)? ('on' FlowResult '->' ResultHandler)*
FlowResult ::= ':end' | ':cancel' | ':error'
ResultHandler ::= ContextOperation? TargetReference
ContextOperation ::= 'append' 'result' 'to' ContextVariable | 'set' ContextVariable 'to' 'result' | 'merge' 'result' 'into' ContextVariable
ContextVariable ::= VARIABLE | PROPERTY_ACCESS
TargetReference ::= IDENTIFIER | VARIABLE | PROPERTY_ACCESS | FlowTermination
FlowTermination ::= ':end' | ':cancel' | ':error'3.5 File Structure
Section titled “3.5 File Structure”RclFile ::= (ImportStatement)* (Section)*
ImportStatement ::= 'import' ImportPath ('as' IDENTIFIER)?
ImportPath ::= IDENTIFIER ('/' IDENTIFIER)*4. Type System
Section titled “4. Type System”4.1 Identifier Rules
Section titled “4.1 Identifier Rules”IDENTIFIER (Title Case):
- Must start with uppercase letter (A-Z)
- Can contain letters, numbers, hyphens, underscores
- Spaces allowed between Title Case words
- Examples:
Welcome Message,User-Profile,Order ID 123
ATTRIBUTE_KEY (lowerCamelCase):
- Must start with lowercase letter (a-z)
- Can contain letters, numbers, underscore
- Examples:
displayName,messageType,user_id
SECTION_TYPE (lowercase):
- Must start with lowercase letter
- Examples:
agent,config,flow,messages,on
4.2 Type Tags
Section titled “4.2 Type Tags”| Type | Aliases | Examples | Notes |
|---|---|---|---|
email | - | <email user@example.com> | |
phone | msisdn | <phone +1234567890> | |
url | - | <url https://example.com> | |
time | t | <time 4pm | UTC> | Default UTC |
datetime | date, dt | <datetime 2024-07-26>, <datetime +5m> | Relative times supported |
zipcode | zip | <zip 94103>, <zip 25585-460 | BR> | |
duration | ttl | <duration P1D>, <ttl 3600s> | ISO 8601 or seconds |
money | - | <money 3.50>, <money 10.99 | USD> | Default USD |
5. Semantic Rules
Section titled “5. Semantic Rules”5.1 File Structure
Section titled “5.1 File Structure”- Files may contain imports followed by sections
- All semantic validation happens at a higher level
- RCL is purely a data representation language
5.2 Section Semantics
Section titled “5.2 Section Semantics”- Sections are generic containers mapping to objects
- Section type is just a string identifier
- Implicit ID: If no ID provided, title-case the section type
- No reserved names at the syntax level
5.3 Value Contextualization
Section titled “5.3 Value Contextualization”- Any value can be contextualized with
withkeyword - Creates a value-context pair for semantic processing
- Context is a map of key-value parameters
5.4 Spread Semantics
Section titled “5.4 Spread Semantics”...IDincludes all attributes from referenced section- Works across imports with proper scoping
- Applied before local attributes (can be overridden)
5.5 Variable Scoping
Section titled “5.5 Variable Scoping”- Variables (
@name) reference runtime context - Property access (
@obj.prop) navigates context objects - Context provided by runtime environment
5.6 Flow Control Extensions
Section titled “5.6 Flow Control Extensions”5.6.1 Flow Invocation Semantics
Section titled “5.6.1 Flow Invocation Semantics”start FlowNameinitiates execution of another flow- Parameters passed with
withclause become flow's parameter context - Flow invocation pushes current state onto execution stack
- Execution continues in the invoked flow's initial state
5.6.2 Result Handling
Section titled “5.6.2 Result Handling”- Three flow termination outcomes:
:end,:cancel,:error :endindicates successful completion and returns flow context:cancelindicates user cancellation, no context returned:errorindicates execution error, optional error context returned
5.6.3 Context Operations
Section titled “5.6.3 Context Operations”append result to @var- Adds result to array (creates if needed)set @var to result- Overwrites variable with resultmerge result into @var- Merges result object into existing object- Operations applied after flow completion before transitioning
5.6.4 Context Scoping for Multi-Flow
Section titled “5.6.4 Context Scoping for Multi-Flow”Variable resolution follows precedence order:
- Flow parameters (highest priority)
- Flow context (local to current flow)
- Conversation context (global, persistent)
5.6.5 Flow Termination
Section titled “5.6.5 Flow Termination”- Flows terminate explicitly using
:end,:cancel, or:error - Termination returns control to parent flow's result handler
- Context isolation maintained between flows
6. Examples
Section titled “6. Examples”6.1 Generic RCL Structure
Section titled “6.1 Generic RCL Structure”# Import exampleimport Common/Config as BaseConfig
# Any section type with any attributesagent Coffee Shop displayName: "Quick Coffee" brandName: "QuickCo"
config ...BaseConfig # Spread from import description: "Order coffee for pickup" phoneNumber: <phone +1-555-0123>
# Nested sectionsflow Main Flow start: Welcome
on Welcome match @reply.text "Order" -> Menu "Hours" -> Info :default -> Welcome
# Section with various content typesmessages Messages text Welcome "Welcome to #{@shopName}!" suggestions reply "Order Coffee" reply "Store Hours"6.2 Collections and Types
Section titled “6.2 Collections and Types”# Listsitems: ("coffee", "tea", "juice")prices: 3.50, 4.00, 2.50 # Parentheses optional
# Block listmenu: - "Espresso" - "Cappuccino" - "Latte"
# Dictionaryorder: {item: "Latte", size: "Large", price: <money 5.50>}
# Block dictionarycustomer: name: "John Doe" phone: <phone +1234567890> member: True6.3 Multi-line Strings
Section titled “6.3 Multi-line Strings”# Triple quotesmessage: """ Thank you for your order! Your #{@item} will be ready in 5 minutes."""
# Pipe notation with controldescription: | This is a multi-line description with clean formatting|
code: +|+ def process_order(item): return f"Processing {item}"|6.4 Flow Control Examples
Section titled “6.4 Flow Control Examples”Basic Flow Invocation
Section titled “Basic Flow Invocation”flow MainFlow on Welcome match @reply.text "Start Order" -> start OrderFlow on :end -> append result to @orders -> ConfirmOrders on :cancel -> Welcome on :error -> ErrorHandlerFlow with Parameters
Section titled “Flow with Parameters”flow PaymentFlow on SelectPayment "Credit Card" -> start PaymentProcessing with amount: @totalPrice, method: "card" on :end -> set @receipt to result -> ShowReceipt on :cancel -> SelectPayment on :error -> PaymentFailedNested Flow Calls
Section titled “Nested Flow Calls”flow OrderFlow on SelectItems "Add Coffee" -> start CoffeeFlow on :end -> start PaymentFlow with items: result on :end -> merge result into @order -> CompleteOrder on :cancel -> SelectItems on :cancel -> SelectItemsFlow Termination
Section titled “Flow Termination”flow CoffeeFlow on Confirmation match @reply.text "Confirm" -> :end # Return flow context "Cancel" -> :cancel # Cancel without changes "Error" -> :error # Error terminationContext Operations
Section titled “Context Operations”flow MultiItemOrder on AddItem "Add Coffee" -> start ItemFlow on :end -> append result to @cartItems -> AddItem "Add Food" -> start FoodFlow on :end -> append result to @cartItems -> AddItem "Checkout" -> merge @cartItems into @order -> ProcessOrder