Operators in CDDL modify or constrain types, providing additional semantics beyond basic type definitions. This document explains how operators are represented in the AST.
In the AST, an operator is represented by the following structure:
export type OperatorType = 'default' | 'size' | 'regexp' | 'bits' | 'and' | 'within' | 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'ge'
export interface Operator {
Type: OperatorType
Value: PropertyType
}
Where:
Type
: The type of operatorValue
: The value or constraint applied by the operatorCDDL supports the following operators, represented in the AST:
default
: Specifies a default value for a typesize
: Constrains the size of a value (e.g., for strings or arrays)regexp
: Specifies a regular expression pattern for stringsbits
: Specifies a bit mask for integersand
: Logical AND operation between typeswithin
: Specifies that a value must be within another valueeq
: Equality comparisonne
: Inequality comparisonlt
: Less than comparisonle
: Less than or equal comparisongt
: Greater than comparisonge
: Greater than or equal comparisonOperators can be attached to:
{
"Type": "variable",
"Name": "ip4",
"PropertyType": [{
"Type": "bstr",
"Operator": {
"Type": "size",
"Value": {
"Type": "literal",
"Value": 4,
"Unwrapped": false
}
}
}]
}
{
"HasCut": true,
"Name": "orientation",
"Type": [
{
"Type": "literal",
"Value": "portrait",
"Unwrapped": false
},
{
"Type": "literal",
"Value": "landscape",
"Unwrapped": false
}
],
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": "portrait",
"Unwrapped": false
}
}
}
{
"HasCut": true,
"Name": "optional",
"Type": [
{
"Type": "tstr",
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": "foobar",
"Unwrapped": false
}
}
}
]
}
The .default
operator specifies a default value for an optional field:
optional = tstr .default "foobar"
AST representation:
{
"Type": "variable",
"Name": "optional",
"IsChoiceAddition": false,
"PropertyType": [
{
"Type": "tstr",
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": "foobar",
"Unwrapped": false
}
}
}
],
"Comments": []
}
The .size
operator constrains the size of a value:
ip4 = bstr .size 4
AST representation:
{
"Type": "variable",
"Name": "ip4",
"IsChoiceAddition": false,
"PropertyType": [
{
"Type": "bstr",
"Operator": {
"Type": "size",
"Value": {
"Type": "literal",
"Value": 4,
"Unwrapped": false
}
}
}
],
"Comments": []
}
The .size
operator can also use a range:
label = bstr .size (1..63)
AST representation:
{
"Type": "variable",
"Name": "label",
"IsChoiceAddition": false,
"PropertyType": [
{
"Type": "bstr",
"Operator": {
"Type": "size",
"Value": {
"Type": "range",
"Value": {
"Min": 1,
"Max": 63,
"Inclusive": true
},
"Unwrapped": false
}
}
}
],
"Comments": []
}
The .regexp
operator specifies a pattern for text strings:
nai = tstr .regexp "[A-Za-z0-9]+@[A-Za-z0-9]+(\.[A-Za-z0-9]+)+"
AST representation:
{
"Type": "variable",
"Name": "nai",
"IsChoiceAddition": false,
"PropertyType": [
{
"Type": "tstr",
"Operator": {
"Type": "regexp",
"Value": {
"Type": "literal",
"Value": "[A-Za-z0-9]+@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)+",
"Unwrapped": false
}
}
}
],
"Comments": []
}
The .ge
, .gt
, .le
, .lt
, .eq
, and .ne
operators specify numerical constraints:
speed = number .ge 0
AST representation:
{
"Type": "variable",
"Name": "speed",
"IsChoiceAddition": false,
"PropertyType": [
{
"Type": {
"Type": "group",
"Value": "number",
"Unwrapped": false
},
"Operator": {
"Type": "ge",
"Value": {
"Type": "literal",
"Value": 0,
"Unwrapped": false
}
}
}
],
"Comments": []
}
The .and
and .within
operators combine constraints:
foo = ip4 .and nai
AST representation:
{
"Type": "variable",
"Name": "foo",
"IsChoiceAddition": false,
"PropertyType": [
{
"Type": {
"Type": "group",
"Value": "ip4",
"Unwrapped": false
},
"Operator": {
"Type": "and",
"Value": {
"Type": "group",
"Value": "nai",
"Unwrapped": false
}
}
}
],
"Comments": []
}
Operators can be applied to properties in groups:
someGroup = {
optional: tstr .default "foobar" ?,
orientation: ("portrait" / "landscape") .default "portrait" ?,
scale: (0.1..2) .default 1 ?,
shrinkToFit: bool .default true ?
}
AST representation:
{
"Type": "group",
"Name": "someGroup",
"IsChoiceAddition": false,
"Properties": [
{
"HasCut": true,
"Occurrence": { "n": 0, "m": Infinity },
"Name": "optional",
"Type": [
{
"Type": "tstr",
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": "foobar",
"Unwrapped": false
}
}
}
],
"Comments": []
},
{
"HasCut": true,
"Occurrence": { "n": 0, "m": Infinity },
"Name": "orientation",
"Type": [
{
"Type": "literal",
"Value": "portrait",
"Unwrapped": false
},
{
"Type": "literal",
"Value": "landscape",
"Unwrapped": false
}
],
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": "portrait",
"Unwrapped": false
}
},
"Comments": []
},
{
"HasCut": true,
"Occurrence": { "n": 0, "m": Infinity },
"Name": "scale",
"Type": [
{
"Type": {
"Type": "range",
"Value": {
"Min": 0.1,
"Max": 2,
"Inclusive": true
},
"Unwrapped": false
},
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": 1,
"Unwrapped": false
}
}
}
],
"Comments": []
},
{
"HasCut": true,
"Occurrence": { "n": 0, "m": Infinity },
"Name": "shrinkToFit",
"Type": [
{
"Type": "bool",
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": true,
"Unwrapped": false
}
}
}
],
"Comments": []
}
],
"Comments": []
}
There are two common patterns for where operators appear in the AST:
Operator
field being part of the type:
{
"Type": "tstr",
"Operator": {
"Type": "default",
"Value": {
"Type": "literal",
"Value": "foobar",
"Unwrapped": false
}
}
}
Operator
field being part of the property:
{
"HasCut": true,
"Name": "orientation",
"Type": [...],
"Operator": {
"Type": "default",
"Value": {...}
}
}
By understanding these operator representations in the AST, you can properly interpret and process CDDL constraints for further transformation or analysis.